-
#
-
# = base64.rb: methods for base64-encoding and -decoding strings
-
#
-
-
# The Base64 module provides for the encoding (#encode64, #strict_encode64,
-
# #urlsafe_encode64) and decoding (#decode64, #strict_decode64,
-
# #urlsafe_decode64) of binary data using a Base64 representation.
-
#
-
# == Example
-
#
-
# A simple encoding and decoding.
-
#
-
# require "base64"
-
#
-
# enc = Base64.encode64('Send reinforcements')
-
# # -> "U2VuZCByZWluZm9yY2VtZW50cw==\n"
-
# plain = Base64.decode64(enc)
-
# # -> "Send reinforcements"
-
#
-
# The purpose of using base64 to encode data is that it translates any
-
# binary data into purely printable characters.
-
-
1
module Base64
-
1
module_function
-
-
# Returns the Base64-encoded version of +bin+.
-
# This method complies with RFC 2045.
-
# Line feeds are added to every 60 encoded charactors.
-
#
-
# require 'base64'
-
# Base64.encode64("Now is the time for all good coders\nto learn Ruby")
-
#
-
# <i>Generates:</i>
-
#
-
# Tm93IGlzIHRoZSB0aW1lIGZvciBhbGwgZ29vZCBjb2RlcnMKdG8gbGVhcm4g
-
# UnVieQ==
-
1
def encode64(bin)
-
10
[bin].pack("m")
-
end
-
-
# Returns the Base64-decoded version of +str+.
-
# This method complies with RFC 2045.
-
# Characters outside the base alphabet are ignored.
-
#
-
# require 'base64'
-
# str = 'VGhpcyBpcyBsaW5lIG9uZQpUaGlzIG' +
-
# 'lzIGxpbmUgdHdvClRoaXMgaXMgbGlu' +
-
# 'ZSB0aHJlZQpBbmQgc28gb24uLi4K'
-
# puts Base64.decode64(str)
-
#
-
# <i>Generates:</i>
-
#
-
# This is line one
-
# This is line two
-
# This is line three
-
# And so on...
-
1
def decode64(str)
-
1
str.unpack("m").first
-
end
-
-
# Returns the Base64-encoded version of +bin+.
-
# This method complies with RFC 4648.
-
# No line feeds are added.
-
1
def strict_encode64(bin)
-
[bin].pack("m0")
-
end
-
-
# Returns the Base64-decoded version of +str+.
-
# This method complies with RFC 4648.
-
# ArgumentError is raised if +str+ is incorrectly padded or contains
-
# non-alphabet characters. Note that CR or LF are also rejected.
-
1
def strict_decode64(str)
-
str.unpack("m0").first
-
end
-
-
# Returns the Base64-encoded version of +bin+.
-
# This method complies with ``Base 64 Encoding with URL and Filename Safe
-
# Alphabet'' in RFC 4648.
-
# The alphabet uses '-' instead of '+' and '_' instead of '/'.
-
1
def urlsafe_encode64(bin)
-
strict_encode64(bin).tr("+/", "-_")
-
end
-
-
# Returns the Base64-decoded version of +str+.
-
# This method complies with ``Base 64 Encoding with URL and Filename Safe
-
# Alphabet'' in RFC 4648.
-
# The alphabet uses '-' instead of '+' and '_' instead of '/'.
-
1
def urlsafe_decode64(str)
-
strict_decode64(str.tr("-_", "+/"))
-
end
-
end
-
#--
-
# benchmark.rb - a performance benchmarking library
-
#
-
# $Id: benchmark.rb 32269 2011-06-28 06:09:46Z naruse $
-
#
-
# Created by Gotoken (gotoken@notwork.org).
-
#
-
# Documentation by Gotoken (original RD), Lyle Johnson (RDoc conversion), and
-
# Gavin Sinclair (editing).
-
#++
-
#
-
# == Overview
-
#
-
# The Benchmark module provides methods for benchmarking Ruby code, giving
-
# detailed reports on the time taken for each task.
-
#
-
-
# The Benchmark module provides methods to measure and report the time
-
# used to execute Ruby code.
-
#
-
# * Measure the time to construct the string given by the expression
-
# <tt>"a"*1_000_000</tt>:
-
#
-
# require 'benchmark'
-
#
-
# puts Benchmark.measure { "a"*1_000_000 }
-
#
-
# On my machine (FreeBSD 3.2 on P5, 100MHz) this generates:
-
#
-
# 1.166667 0.050000 1.216667 ( 0.571355)
-
#
-
# This report shows the user CPU time, system CPU time, the sum of
-
# the user and system CPU times, and the elapsed real time. The unit
-
# of time is seconds.
-
#
-
# * Do some experiments sequentially using the #bm method:
-
#
-
# require 'benchmark'
-
#
-
# n = 50000
-
# Benchmark.bm do |x|
-
# x.report { for i in 1..n; a = "1"; end }
-
# x.report { n.times do ; a = "1"; end }
-
# x.report { 1.upto(n) do ; a = "1"; end }
-
# end
-
#
-
# The result:
-
#
-
# user system total real
-
# 1.033333 0.016667 1.016667 ( 0.492106)
-
# 1.483333 0.000000 1.483333 ( 0.694605)
-
# 1.516667 0.000000 1.516667 ( 0.711077)
-
#
-
# * Continuing the previous example, put a label in each report:
-
#
-
# require 'benchmark'
-
#
-
# n = 50000
-
# Benchmark.bm(7) do |x|
-
# x.report("for:") { for i in 1..n; a = "1"; end }
-
# x.report("times:") { n.times do ; a = "1"; end }
-
# x.report("upto:") { 1.upto(n) do ; a = "1"; end }
-
# end
-
#
-
# The result:
-
#
-
# user system total real
-
# for: 1.050000 0.000000 1.050000 ( 0.503462)
-
# times: 1.533333 0.016667 1.550000 ( 0.735473)
-
# upto: 1.500000 0.016667 1.516667 ( 0.711239)
-
#
-
#
-
# * The times for some benchmarks depend on the order in which items
-
# are run. These differences are due to the cost of memory
-
# allocation and garbage collection. To avoid these discrepancies,
-
# the #bmbm method is provided. For example, to compare ways to
-
# sort an array of floats:
-
#
-
# require 'benchmark'
-
#
-
# array = (1..1000000).map { rand }
-
#
-
# Benchmark.bmbm do |x|
-
# x.report("sort!") { array.dup.sort! }
-
# x.report("sort") { array.dup.sort }
-
# end
-
#
-
# The result:
-
#
-
# Rehearsal -----------------------------------------
-
# sort! 11.928000 0.010000 11.938000 ( 12.756000)
-
# sort 13.048000 0.020000 13.068000 ( 13.857000)
-
# ------------------------------- total: 25.006000sec
-
#
-
# user system total real
-
# sort! 12.959000 0.010000 12.969000 ( 13.793000)
-
# sort 12.007000 0.000000 12.007000 ( 12.791000)
-
#
-
#
-
# * Report statistics of sequential experiments with unique labels,
-
# using the #benchmark method:
-
#
-
# require 'benchmark'
-
# include Benchmark # we need the CAPTION and FORMAT constants
-
#
-
# n = 50000
-
# Benchmark.benchmark(CAPTION, 7, FORMAT, ">total:", ">avg:") do |x|
-
# tf = x.report("for:") { for i in 1..n; a = "1"; end }
-
# tt = x.report("times:") { n.times do ; a = "1"; end }
-
# tu = x.report("upto:") { 1.upto(n) do ; a = "1"; end }
-
# [tf+tt+tu, (tf+tt+tu)/3]
-
# end
-
#
-
# The result:
-
#
-
# user system total real
-
# for: 1.016667 0.016667 1.033333 ( 0.485749)
-
# times: 1.450000 0.016667 1.466667 ( 0.681367)
-
# upto: 1.533333 0.000000 1.533333 ( 0.722166)
-
# >total: 4.000000 0.033333 4.033333 ( 1.889282)
-
# >avg: 1.333333 0.011111 1.344444 ( 0.629761)
-
-
1
module Benchmark
-
-
1
BENCHMARK_VERSION = "2002-04-25" #:nodoc"
-
-
# Invokes the block with a <tt>Benchmark::Report</tt> object, which
-
# may be used to collect and report on the results of individual
-
# benchmark tests. Reserves <i>label_width</i> leading spaces for
-
# labels on each line. Prints _caption_ at the top of the
-
# report, and uses _format_ to format each line.
-
# Returns an array of Benchmark::Tms objects.
-
#
-
# If the block returns an array of
-
# <tt>Benchmark::Tms</tt> objects, these will be used to format
-
# additional lines of output. If _label_ parameters are
-
# given, these are used to label these extra lines.
-
#
-
# _Note_: Other methods provide a simpler interface to this one, and are
-
# suitable for nearly all benchmarking requirements. See the examples in
-
# Benchmark, and the #bm and #bmbm methods.
-
#
-
# Example:
-
#
-
# require 'benchmark'
-
# include Benchmark # we need the CAPTION and FORMAT constants
-
#
-
# n = 50000
-
# Benchmark.benchmark(CAPTION, 7, FORMAT, ">total:", ">avg:") do |x|
-
# tf = x.report("for:") { for i in 1..n; a = "1"; end }
-
# tt = x.report("times:") { n.times do ; a = "1"; end }
-
# tu = x.report("upto:") { 1.upto(n) do ; a = "1"; end }
-
# [tf+tt+tu, (tf+tt+tu)/3]
-
# end
-
#
-
# <i>Generates:</i>
-
#
-
# user system total real
-
# for: 1.016667 0.016667 1.033333 ( 0.485749)
-
# times: 1.450000 0.016667 1.466667 ( 0.681367)
-
# upto: 1.533333 0.000000 1.533333 ( 0.722166)
-
# >total: 4.000000 0.033333 4.033333 ( 1.889282)
-
# >avg: 1.333333 0.011111 1.344444 ( 0.629761)
-
#
-
-
1
def benchmark(caption = "", label_width = nil, format = nil, *labels) # :yield: report
-
sync = STDOUT.sync
-
STDOUT.sync = true
-
label_width ||= 0
-
label_width += 1
-
format ||= FORMAT
-
print ' '*label_width + caption
-
report = Report.new(label_width, format)
-
results = yield(report)
-
Array === results and results.grep(Tms).each {|t|
-
print((labels.shift || t.label || "").ljust(label_width), t.format(format))
-
}
-
report.list
-
ensure
-
STDOUT.sync = sync unless sync.nil?
-
end
-
-
-
# A simple interface to the #benchmark method, #bm is generates sequential reports
-
# with labels. The parameters have the same meaning as for #benchmark.
-
#
-
# require 'benchmark'
-
#
-
# n = 50000
-
# Benchmark.bm(7) do |x|
-
# x.report("for:") { for i in 1..n; a = "1"; end }
-
# x.report("times:") { n.times do ; a = "1"; end }
-
# x.report("upto:") { 1.upto(n) do ; a = "1"; end }
-
# end
-
#
-
# <i>Generates:</i>
-
#
-
# user system total real
-
# for: 1.050000 0.000000 1.050000 ( 0.503462)
-
# times: 1.533333 0.016667 1.550000 ( 0.735473)
-
# upto: 1.500000 0.016667 1.516667 ( 0.711239)
-
#
-
-
1
def bm(label_width = 0, *labels, &blk) # :yield: report
-
benchmark(CAPTION, label_width, FORMAT, *labels, &blk)
-
end
-
-
-
# Sometimes benchmark results are skewed because code executed
-
# earlier encounters different garbage collection overheads than
-
# that run later. #bmbm attempts to minimize this effect by running
-
# the tests twice, the first time as a rehearsal in order to get the
-
# runtime environment stable, the second time for
-
# real. <tt>GC.start</tt> is executed before the start of each of
-
# the real timings; the cost of this is not included in the
-
# timings. In reality, though, there's only so much that #bmbm can
-
# do, and the results are not guaranteed to be isolated from garbage
-
# collection and other effects.
-
#
-
# Because #bmbm takes two passes through the tests, it can
-
# calculate the required label width.
-
#
-
# require 'benchmark'
-
#
-
# array = (1..1000000).map { rand }
-
#
-
# Benchmark.bmbm do |x|
-
# x.report("sort!") { array.dup.sort! }
-
# x.report("sort") { array.dup.sort }
-
# end
-
#
-
# <i>Generates:</i>
-
#
-
# Rehearsal -----------------------------------------
-
# sort! 11.928000 0.010000 11.938000 ( 12.756000)
-
# sort 13.048000 0.020000 13.068000 ( 13.857000)
-
# ------------------------------- total: 25.006000sec
-
#
-
# user system total real
-
# sort! 12.959000 0.010000 12.969000 ( 13.793000)
-
# sort 12.007000 0.000000 12.007000 ( 12.791000)
-
#
-
# #bmbm yields a Benchmark::Job object and returns an array of
-
# Benchmark::Tms objects.
-
#
-
1
def bmbm(width = 0, &blk) # :yield: job
-
job = Job.new(width)
-
yield(job)
-
width = job.width + 1
-
sync = STDOUT.sync
-
STDOUT.sync = true
-
-
# rehearsal
-
puts 'Rehearsal '.ljust(width+CAPTION.length,'-')
-
ets = job.list.inject(Tms.new) { |sum,(label,item)|
-
print label.ljust(width)
-
res = Benchmark.measure(&item)
-
print res.format
-
sum + res
-
}.format("total: %tsec")
-
print " #{ets}\n\n".rjust(width+CAPTION.length+2,'-')
-
-
# take
-
print ' '*width + CAPTION
-
job.list.map { |label,item|
-
GC.start
-
print label.ljust(width)
-
Benchmark.measure(label, &item).tap { |res| print res }
-
}
-
ensure
-
STDOUT.sync = sync unless sync.nil?
-
end
-
-
#
-
# Returns the time used to execute the given block as a
-
# Benchmark::Tms object.
-
#
-
1
def measure(label = "") # :yield:
-
329
t0, r0 = Process.times, Time.now
-
329
yield
-
327
t1, r1 = Process.times, Time.now
-
327
Benchmark::Tms.new(t1.utime - t0.utime,
-
t1.stime - t0.stime,
-
t1.cutime - t0.cutime,
-
t1.cstime - t0.cstime,
-
r1.to_f - r0.to_f,
-
label)
-
end
-
-
#
-
# Returns the elapsed real time used to execute the given block.
-
#
-
1
def realtime # :yield:
-
4
r0 = Time.now
-
4
yield
-
4
Time.now - r0
-
end
-
-
1
module_function :benchmark, :measure, :realtime, :bm, :bmbm
-
-
#
-
# A Job is a sequence of labelled blocks to be processed by the
-
# Benchmark.bmbm method. It is of little direct interest to the user.
-
#
-
1
class Job # :nodoc:
-
#
-
# Returns an initialized Job instance.
-
# Usually, one doesn't call this method directly, as new
-
# Job objects are created by the #bmbm method.
-
# _width_ is a initial value for the label offset used in formatting;
-
# the #bmbm method passes its _width_ argument to this constructor.
-
#
-
1
def initialize(width)
-
@width = width
-
@list = []
-
end
-
-
#
-
# Registers the given label and block pair in the job list.
-
#
-
1
def item(label = "", &blk) # :yield:
-
raise ArgumentError, "no block" unless block_given?
-
label = label.to_s
-
w = label.length
-
@width = w if @width < w
-
@list << [label, blk]
-
self
-
end
-
-
1
alias report item
-
-
# An array of 2-element arrays, consisting of label and block pairs.
-
1
attr_reader :list
-
-
# Length of the widest label in the #list.
-
1
attr_reader :width
-
end
-
-
#
-
# This class is used by the Benchmark.benchmark and Benchmark.bm methods.
-
# It is of little direct interest to the user.
-
#
-
1
class Report # :nodoc:
-
#
-
# Returns an initialized Report instance.
-
# Usually, one doesn't call this method directly, as new
-
# Report objects are created by the #benchmark and #bm methods.
-
# _width_ and _format_ are the label offset and
-
# format string used by Tms#format.
-
#
-
1
def initialize(width = 0, format = nil)
-
@width, @format, @list = width, format, []
-
end
-
-
#
-
# Prints the _label_ and measured time for the block,
-
# formatted by _format_. See Tms#format for the
-
# formatting rules.
-
#
-
1
def item(label = "", *format, &blk) # :yield:
-
print label.to_s.ljust(@width)
-
@list << res = Benchmark.measure(label, &blk)
-
print res.format(@format, *format)
-
res
-
end
-
-
1
alias report item
-
-
# An array of Benchmark::Tms objects representing each item.
-
1
attr_reader :list
-
end
-
-
-
-
#
-
# A data object, representing the times associated with a benchmark
-
# measurement.
-
#
-
1
class Tms
-
-
# Default caption, see also Benchmark::CAPTION
-
1
CAPTION = " user system total real\n"
-
-
# Default format string, see also Benchmark::FORMAT
-
1
FORMAT = "%10.6u %10.6y %10.6t %10.6r\n"
-
-
# User CPU time
-
1
attr_reader :utime
-
-
# System CPU time
-
1
attr_reader :stime
-
-
# User CPU time of children
-
1
attr_reader :cutime
-
-
# System CPU time of children
-
1
attr_reader :cstime
-
-
# Elapsed real time
-
1
attr_reader :real
-
-
# Total time, that is _utime_ + _stime_ + _cutime_ + _cstime_
-
1
attr_reader :total
-
-
# Label
-
1
attr_reader :label
-
-
#
-
# Returns an initialized Tms object which has
-
# _utime_ as the user CPU time, _stime_ as the system CPU time,
-
# _cutime_ as the children's user CPU time, _cstime_ as the children's
-
# system CPU time, _real_ as the elapsed real time and _label_ as the label.
-
#
-
1
def initialize(utime = 0.0, stime = 0.0, cutime = 0.0, cstime = 0.0, real = 0.0, label = nil)
-
327
@utime, @stime, @cutime, @cstime, @real, @label = utime, stime, cutime, cstime, real, label.to_s
-
327
@total = @utime + @stime + @cutime + @cstime
-
end
-
-
#
-
# Returns a new Tms object whose times are the sum of the times for this
-
# Tms object, plus the time required to execute the code block (_blk_).
-
#
-
1
def add(&blk) # :yield:
-
self + Benchmark.measure(&blk)
-
end
-
-
#
-
# An in-place version of #add.
-
#
-
1
def add!(&blk)
-
t = Benchmark.measure(&blk)
-
@utime = utime + t.utime
-
@stime = stime + t.stime
-
@cutime = cutime + t.cutime
-
@cstime = cstime + t.cstime
-
@real = real + t.real
-
self
-
end
-
-
#
-
# Returns a new Tms object obtained by memberwise summation
-
# of the individual times for this Tms object with those of the other
-
# Tms object.
-
# This method and #/() are useful for taking statistics.
-
#
-
1
def +(other); memberwise(:+, other) end
-
-
#
-
# Returns a new Tms object obtained by memberwise subtraction
-
# of the individual times for the other Tms object from those of this
-
# Tms object.
-
#
-
1
def -(other); memberwise(:-, other) end
-
-
#
-
# Returns a new Tms object obtained by memberwise multiplication
-
# of the individual times for this Tms object by _x_.
-
#
-
1
def *(x); memberwise(:*, x) end
-
-
#
-
# Returns a new Tms object obtained by memberwise division
-
# of the individual times for this Tms object by _x_.
-
# This method and #+() are useful for taking statistics.
-
#
-
1
def /(x); memberwise(:/, x) end
-
-
#
-
# Returns the contents of this Tms object as
-
# a formatted string, according to a format string
-
# like that passed to Kernel.format. In addition, #format
-
# accepts the following extensions:
-
#
-
# <tt>%u</tt>:: Replaced by the user CPU time, as reported by Tms#utime.
-
# <tt>%y</tt>:: Replaced by the system CPU time, as reported by #stime (Mnemonic: y of "s*y*stem")
-
# <tt>%U</tt>:: Replaced by the children's user CPU time, as reported by Tms#cutime
-
# <tt>%Y</tt>:: Replaced by the children's system CPU time, as reported by Tms#cstime
-
# <tt>%t</tt>:: Replaced by the total CPU time, as reported by Tms#total
-
# <tt>%r</tt>:: Replaced by the elapsed real time, as reported by Tms#real
-
# <tt>%n</tt>:: Replaced by the label string, as reported by Tms#label (Mnemonic: n of "*n*ame")
-
#
-
# If _format_ is not given, FORMAT is used as default value, detailing the
-
# user, system and real elapsed time.
-
#
-
1
def format(format = nil, *args)
-
str = (format || FORMAT).dup
-
str.gsub!(/(%[-+\.\d]*)n/) { "#{$1}s" % label }
-
str.gsub!(/(%[-+\.\d]*)u/) { "#{$1}f" % utime }
-
str.gsub!(/(%[-+\.\d]*)y/) { "#{$1}f" % stime }
-
str.gsub!(/(%[-+\.\d]*)U/) { "#{$1}f" % cutime }
-
str.gsub!(/(%[-+\.\d]*)Y/) { "#{$1}f" % cstime }
-
str.gsub!(/(%[-+\.\d]*)t/) { "#{$1}f" % total }
-
str.gsub!(/(%[-+\.\d]*)r/) { "(#{$1}f)" % real }
-
format ? str % args : str
-
end
-
-
#
-
# Same as #format.
-
#
-
1
def to_s
-
format
-
end
-
-
#
-
# Returns a new 6-element array, consisting of the
-
# label, user CPU time, system CPU time, children's
-
# user CPU time, children's system CPU time and elapsed
-
# real time.
-
#
-
1
def to_a
-
[@label, @utime, @stime, @cutime, @cstime, @real]
-
end
-
-
1
protected
-
-
#
-
# Returns a new Tms object obtained by memberwise operation +op+
-
# of the individual times for this Tms object with those of the other
-
# Tms object.
-
#
-
# +op+ can be a mathematical operation such as <tt>+</tt>, <tt>-</tt>,
-
# <tt>*</tt>, <tt>/</tt>
-
#
-
1
def memberwise(op, x)
-
case x
-
when Benchmark::Tms
-
Benchmark::Tms.new(utime.__send__(op, x.utime),
-
stime.__send__(op, x.stime),
-
cutime.__send__(op, x.cutime),
-
cstime.__send__(op, x.cstime),
-
real.__send__(op, x.real)
-
)
-
else
-
Benchmark::Tms.new(utime.__send__(op, x),
-
stime.__send__(op, x),
-
cutime.__send__(op, x),
-
cstime.__send__(op, x),
-
real.__send__(op, x)
-
)
-
end
-
end
-
end
-
-
# The default caption string (heading above the output times).
-
1
CAPTION = Benchmark::Tms::CAPTION
-
-
# The default format string used to display times. See also Benchmark::Tms#format.
-
1
FORMAT = Benchmark::Tms::FORMAT
-
end
-
-
1
if __FILE__ == $0
-
include Benchmark
-
-
n = ARGV[0].to_i.nonzero? || 50000
-
puts %Q([#{n} times iterations of `a = "1"'])
-
benchmark(" " + CAPTION, 7, FORMAT) do |x|
-
x.report("for:") {for _ in 1..n; _ = "1"; end} # Benchmark.measure
-
x.report("times:") {n.times do ; _ = "1"; end}
-
x.report("upto:") {1.upto(n) do ; _ = "1"; end}
-
end
-
-
benchmark do
-
[
-
measure{for _ in 1..n; _ = "1"; end}, # Benchmark.measure
-
measure{n.times do ; _ = "1"; end},
-
measure{1.upto(n) do ; _ = "1"; end}
-
]
-
end
-
end
-
1
class Integer < Numeric
-
# call-seq:
-
# int.to_d -> bigdecimal
-
#
-
# Convert +int+ to a BigDecimal and return it.
-
#
-
# require 'bigdecimal'
-
# require 'bigdecimal/util'
-
#
-
# 42.to_d
-
# # => #<BigDecimal:1008ef070,'0.42E2',9(36)>
-
#
-
1
def to_d
-
1
BigDecimal(self)
-
end
-
end
-
-
1
class Float < Numeric
-
# call-seq:
-
# flt.to_d(precision=nil) -> bigdecimal
-
#
-
# Convert +flt+ to a BigDecimal and return it.
-
#
-
# require 'bigdecimal'
-
# require 'bigdecimal/util'
-
#
-
# 0.5.to_d
-
# # => #<BigDecimal:1dc69e0,'0.5E0',9(18)>
-
#
-
1
def to_d(precision=nil)
-
8
BigDecimal(self, precision || Float::DIG+1)
-
end
-
end
-
-
1
class String
-
# call-seq:
-
# string.to_d -> bigdecimal
-
#
-
# Convert +string+ to a BigDecimal and return it.
-
#
-
# require 'bigdecimal'
-
# require 'bigdecimal/util'
-
#
-
# "0.5".to_d
-
# # => #<BigDecimal:1dc69e0,'0.5E0',9(18)>
-
#
-
1
def to_d
-
79
BigDecimal(self)
-
end
-
end
-
-
1
class BigDecimal < Numeric
-
# call-seq:
-
# a.to_digits -> string
-
#
-
# Converts a BigDecimal to a String of the form "nnnnnn.mmm".
-
# This method is deprecated; use BigDecimal#to_s("F") instead.
-
#
-
# require 'bigdecimal'
-
# require 'bigdecimal/util'
-
#
-
# d = BigDecimal.new("3.14")
-
# d.to_digits
-
# # => "3.14"
-
1
def to_digits
-
if self.nan? || self.infinite? || self.zero?
-
self.to_s
-
else
-
i = self.to_i.to_s
-
_,f,_,z = self.frac.split
-
i + "." + ("0"*(-z)) + f
-
end
-
end
-
-
# call-seq:
-
# a.to_d -> bigdecimal
-
#
-
# Returns self.
-
1
def to_d
-
self
-
end
-
end
-
-
1
class Rational < Numeric
-
# call-seq:
-
# r.to_d(sig) -> bigdecimal
-
#
-
# Converts a Rational to a BigDecimal. Takes an optional parameter +sig+ to
-
# limit the amount of significant digits.
-
# If a negative precision is given, raise ArgumentError.
-
# The zero precision and implicit precision is deprecated.
-
#
-
# r = (22/7.0).to_r
-
# # => (7077085128725065/2251799813685248)
-
# r.to_d
-
# # => #<BigDecimal:1a52bd8,'0.3142857142 8571427937 0154144999 105E1',45(63)>
-
# r.to_d(3)
-
# # => #<BigDecimal:1a44d08,'0.314E1',18(36)>
-
1
def to_d(precision=0)
-
if precision < 0
-
raise ArgumentError, "negative precision"
-
elsif precision == 0
-
warn "zero and implicit precision is deprecated."
-
precision = BigDecimal.double_fig*2+1
-
end
-
num = self.numerator
-
BigDecimal(num).div(self.denominator, precision)
-
end
-
end
-
# = delegate -- Support for the Delegation Pattern
-
#
-
# Documentation by James Edward Gray II and Gavin Sinclair
-
-
##
-
# This library provides three different ways to delegate method calls to an
-
# object. The easiest to use is SimpleDelegator. Pass an object to the
-
# constructor and all methods supported by the object will be delegated. This
-
# object can be changed later.
-
#
-
# Going a step further, the top level DelegateClass method allows you to easily
-
# setup delegation through class inheritance. This is considerably more
-
# flexible and thus probably the most common use for this library.
-
#
-
# Finally, if you need full control over the delegation scheme, you can inherit
-
# from the abstract class Delegator and customize as needed. (If you find
-
# yourself needing this control, have a look at Forwardable which is also in
-
# the standard library. It may suit your needs better.)
-
#
-
# SimpleDelegator's implementation serves as a nice example if the use of
-
# Delegator:
-
#
-
# class SimpleDelegator < Delegator
-
# def initialize(obj)
-
# super # pass obj to Delegator constructor, required
-
# @delegate_sd_obj = obj # store obj for future use
-
# end
-
#
-
# def __getobj__
-
# @delegate_sd_obj # return object we are delegating to, required
-
# end
-
#
-
# def __setobj__(obj)
-
# @delegate_sd_obj = obj # change delegation object,
-
# # a feature we're providing
-
# end
-
# end
-
#
-
# == Notes
-
#
-
# Be advised, RDoc will not detect delegated methods.
-
#
-
1
class Delegator < BasicObject
-
1
kernel = ::Kernel.dup
-
1
kernel.class_eval do
-
1
[:to_s,:inspect,:=~,:!~,:===,:<=>,:eql?,:hash].each do |m|
-
8
undef_method m
-
end
-
end
-
1
include kernel
-
-
# :stopdoc:
-
1
def self.const_missing(n)
-
40
::Object.const_get(n)
-
end
-
# :startdoc:
-
-
#
-
# Pass in the _obj_ to delegate method calls to. All methods supported by
-
# _obj_ will be delegated to.
-
#
-
1
def initialize(obj)
-
4
__setobj__(obj)
-
end
-
-
#
-
# Handles the magic of delegation through \_\_getobj\_\_.
-
#
-
1
def method_missing(m, *args, &block)
-
target = self.__getobj__
-
begin
-
target.respond_to?(m) ? target.__send__(m, *args, &block) : super(m, *args, &block)
-
ensure
-
$@.delete_if {|t| %r"\A#{Regexp.quote(__FILE__)}:#{__LINE__-2}:"o =~ t} if $@
-
end
-
end
-
-
#
-
# Checks for a method provided by this the delegate object by forwarding the
-
# call through \_\_getobj\_\_.
-
#
-
1
def respond_to_missing?(m, include_private)
-
r = self.__getobj__.respond_to?(m, include_private)
-
if r && include_private && !self.__getobj__.respond_to?(m, false)
-
warn "#{caller(3)[0]}: delegator does not forward private method \##{m}"
-
return false
-
end
-
r
-
end
-
-
#
-
# Returns the methods available to this delegate object as the union
-
# of this object's and \_\_getobj\_\_ methods.
-
#
-
1
def methods
-
__getobj__.methods | super
-
end
-
-
#
-
# Returns the methods available to this delegate object as the union
-
# of this object's and \_\_getobj\_\_ public methods.
-
#
-
1
def public_methods(all=true)
-
__getobj__.public_methods(all) | super
-
end
-
-
#
-
# Returns the methods available to this delegate object as the union
-
# of this object's and \_\_getobj\_\_ protected methods.
-
#
-
1
def protected_methods(all=true)
-
__getobj__.protected_methods(all) | super
-
end
-
-
# Note: no need to specialize private_methods, since they are not forwarded
-
-
#
-
# Returns true if two objects are considered of equal value.
-
#
-
1
def ==(obj)
-
return true if obj.equal?(self)
-
self.__getobj__ == obj
-
end
-
-
#
-
# Returns true if two objects are not considered of equal value.
-
#
-
1
def !=(obj)
-
return false if obj.equal?(self)
-
__getobj__ != obj
-
end
-
-
1
def !
-
!__getobj__
-
end
-
-
#
-
# This method must be overridden by subclasses and should return the object
-
# method calls are being delegated to.
-
#
-
1
def __getobj__
-
raise NotImplementedError, "need to define `__getobj__'"
-
end
-
-
#
-
# This method must be overridden by subclasses and change the object delegate
-
# to _obj_.
-
#
-
1
def __setobj__(obj)
-
raise NotImplementedError, "need to define `__setobj__'"
-
end
-
-
#
-
# Serialization support for the object returned by \_\_getobj\_\_.
-
#
-
1
def marshal_dump
-
ivars = instance_variables.reject {|var| /\A@delegate_/ =~ var}
-
[
-
:__v2__,
-
ivars, ivars.map{|var| instance_variable_get(var)},
-
__getobj__
-
]
-
end
-
-
#
-
# Reinitializes delegation from a serialized object.
-
#
-
1
def marshal_load(data)
-
version, vars, values, obj = data
-
if version == :__v2__
-
vars.each_with_index{|var, i| instance_variable_set(var, values[i])}
-
__setobj__(obj)
-
else
-
__setobj__(data)
-
end
-
end
-
-
1
def initialize_clone(obj) # :nodoc:
-
self.__setobj__(obj.__getobj__.clone)
-
end
-
1
def initialize_dup(obj) # :nodoc:
-
self.__setobj__(obj.__getobj__.dup)
-
end
-
1
private :initialize_clone, :initialize_dup
-
-
##
-
# :method: trust
-
# Trust both the object returned by \_\_getobj\_\_ and self.
-
#
-
-
##
-
# :method: untrust
-
# Untrust both the object returned by \_\_getobj\_\_ and self.
-
#
-
-
##
-
# :method: taint
-
# Taint both the object returned by \_\_getobj\_\_ and self.
-
#
-
-
##
-
# :method: untaint
-
# Untaint both the object returned by \_\_getobj\_\_ and self.
-
#
-
-
##
-
# :method: freeze
-
# Freeze both the object returned by \_\_getobj\_\_ and self.
-
#
-
-
1
[:trust, :untrust, :taint, :untaint, :freeze].each do |method|
-
5
define_method method do
-
__getobj__.send(method)
-
super()
-
end
-
end
-
-
1
@delegator_api = self.public_instance_methods
-
1
def self.public_api # :nodoc:
-
1
@delegator_api
-
end
-
end
-
-
##
-
# A concrete implementation of Delegator, this class provides the means to
-
# delegate all supported method calls to the object passed into the constructor
-
# and even to change the object being delegated to at a later time with
-
# #__setobj__.
-
#
-
# Here's a simple example that takes advantage of the fact that
-
# SimpleDelegator's delegation object can be changed at any time.
-
#
-
# class Stats
-
# def initialize
-
# @source = SimpleDelegator.new([])
-
# end
-
#
-
# def stats(records)
-
# @source.__setobj__(records)
-
#
-
# "Elements: #{@source.size}\n" +
-
# " Non-Nil: #{@source.compact.size}\n" +
-
# " Unique: #{@source.uniq.size}\n"
-
# end
-
# end
-
#
-
# s = Stats.new
-
# puts s.stats(%w{James Edward Gray II})
-
# puts
-
# puts s.stats([1, 2, 3, nil, 4, 5, 1, 2])
-
#
-
# Prints:
-
#
-
# Elements: 4
-
# Non-Nil: 4
-
# Unique: 4
-
#
-
# Elements: 8
-
# Non-Nil: 7
-
# Unique: 6
-
#
-
1
class SimpleDelegator<Delegator
-
# Returns the current object method calls are being delegated to.
-
1
def __getobj__
-
@delegate_sd_obj
-
end
-
-
#
-
# Changes the delegate object to _obj_.
-
#
-
# It's important to note that this does *not* cause SimpleDelegator's methods
-
# to change. Because of this, you probably only want to change delegation
-
# to objects of the same type as the original delegate.
-
#
-
# Here's an example of changing the delegation object.
-
#
-
# names = SimpleDelegator.new(%w{James Edward Gray II})
-
# puts names[1] # => Edward
-
# names.__setobj__(%w{Gavin Sinclair})
-
# puts names[1] # => Sinclair
-
#
-
1
def __setobj__(obj)
-
raise ArgumentError, "cannot delegate to self" if self.equal?(obj)
-
@delegate_sd_obj = obj
-
end
-
end
-
-
# :stopdoc:
-
1
def Delegator.delegating_block(mid)
-
175
lambda do |*args, &block|
-
8
target = self.__getobj__
-
8
begin
-
8
target.__send__(mid, *args, &block)
-
ensure
-
8
$@.delete_if {|t| /\A#{Regexp.quote(__FILE__)}:#{__LINE__-2}:/o =~ t} if $@
-
end
-
end
-
end
-
# :startdoc:
-
-
#
-
# The primary interface to this library. Use to setup delegation when defining
-
# your class.
-
#
-
# class MyClass < DelegateClass(ClassToDelegateTo) # Step 1
-
# def initialize
-
# super(obj_of_ClassToDelegateTo) # Step 2
-
# end
-
# end
-
#
-
# Here's a sample of use from Tempfile which is really a File object with a
-
# few special rules about storage location and when the File should be
-
# deleted. That makes for an almost textbook perfect example of how to use
-
# delegation.
-
#
-
# class Tempfile < DelegateClass(File)
-
# # constant and class member data initialization...
-
#
-
# def initialize(basename, tmpdir=Dir::tmpdir)
-
# # build up file path/name in var tmpname...
-
#
-
# @tmpfile = File.open(tmpname, File::RDWR|File::CREAT|File::EXCL, 0600)
-
#
-
# # ...
-
#
-
# super(@tmpfile)
-
#
-
# # below this point, all methods of File are supported...
-
# end
-
#
-
# # ...
-
# end
-
#
-
1
def DelegateClass(superclass)
-
1
klass = Class.new(Delegator)
-
1
methods = superclass.instance_methods
-
1
methods -= ::Delegator.public_api
-
1
methods -= [:to_s,:inspect,:=~,:!~,:===]
-
1
klass.module_eval do
-
1
def __getobj__ # :nodoc:
-
8
@delegate_dc_obj
-
end
-
1
def __setobj__(obj) # :nodoc:
-
4
raise ArgumentError, "cannot delegate to self" if self.equal?(obj)
-
4
@delegate_dc_obj = obj
-
end
-
1
methods.each do |method|
-
175
define_method(method, Delegator.delegating_block(method))
-
end
-
end
-
1
klass.define_singleton_method :public_instance_methods do |all=true|
-
super(all) - superclass.protected_instance_methods
-
end
-
1
klass.define_singleton_method :protected_instance_methods do |all=true|
-
super(all) | superclass.protected_instance_methods
-
end
-
1
return klass
-
end
-
-
# :enddoc:
-
-
1
if __FILE__ == $0
-
class ExtArray<DelegateClass(Array)
-
def initialize()
-
super([])
-
end
-
end
-
-
ary = ExtArray.new
-
p ary.class
-
ary.push 25
-
p ary
-
ary.push 42
-
ary.each {|x| p x}
-
-
foo = Object.new
-
def foo.test
-
25
-
end
-
def foo.iter
-
yield self
-
end
-
def foo.error
-
raise 'this is OK'
-
end
-
foo2 = SimpleDelegator.new(foo)
-
p foo2
-
foo2.instance_eval{print "foo\n"}
-
p foo.test == foo2.test # => true
-
p foo2.iter{[55,true]} # => true
-
foo2.error # raise error!
-
end
-
#
-
# ipaddr.rb - A class to manipulate an IP address
-
#
-
# Copyright (c) 2002 Hajimu UMEMOTO <ume@mahoroba.org>.
-
# Copyright (c) 2007 Akinori MUSHA <knu@iDaemons.org>.
-
# All rights reserved.
-
#
-
# You can redistribute and/or modify it under the same terms as Ruby.
-
#
-
# $Id: ipaddr.rb 31686 2011-05-22 02:21:56Z drbrain $
-
#
-
# Contact:
-
# - Akinori MUSHA <knu@iDaemons.org> (current maintainer)
-
#
-
# TODO:
-
# - scope_id support
-
#
-
1
require 'socket'
-
-
1
unless Socket.const_defined? "AF_INET6"
-
class Socket < BasicSocket
-
# IPv6 protocol family
-
AF_INET6 = Object.new
-
end
-
-
class << IPSocket
-
# Returns +true+ if +addr+ is a valid IPv4 address.
-
def valid_v4?(addr)
-
if /\A(\d{1,3})\.(\d{1,3})\.(\d{1,3})\.(\d{1,3})\Z/ =~ addr
-
return $~.captures.all? {|i| i.to_i < 256}
-
end
-
return false
-
end
-
-
# Returns +true+ if +addr+ is a valid IPv6 address.
-
def valid_v6?(addr)
-
# IPv6 (normal)
-
return true if /\A[\dA-Fa-f]{1,4}(:[\dA-Fa-f]{1,4})*\Z/ =~ addr
-
return true if /\A[\dA-Fa-f]{1,4}(:[\dA-Fa-f]{1,4})*::([\dA-Fa-f]{1,4}(:[\dA-Fa-f]{1,4})*)?\Z/ =~ addr
-
return true if /\A::([\dA-Fa-f]{1,4}(:[\dA-Fa-f]{1,4})*)?\Z/ =~ addr
-
# IPv6 (IPv4 compat)
-
return true if /\A[\dA-Fa-f]{1,4}(:[\dA-Fa-f]{1,4})*:/ =~ addr && valid_v4?($')
-
return true if /\A[\dA-Fa-f]{1,4}(:[\dA-Fa-f]{1,4})*::([\dA-Fa-f]{1,4}(:[\dA-Fa-f]{1,4})*:)?/ =~ addr && valid_v4?($')
-
return true if /\A::([\dA-Fa-f]{1,4}(:[\dA-Fa-f]{1,4})*:)?/ =~ addr && valid_v4?($')
-
-
false
-
end
-
-
# Returns +true+ if +addr+ is either a valid IPv4 or IPv6 address.
-
def valid?(addr)
-
valid_v4?(addr) || valid_v6?(addr)
-
end
-
-
alias getaddress_orig getaddress
-
-
# Returns a +String+ based representation of a valid DNS hostname,
-
# IPv4 or IPv6 address.
-
#
-
# IPSocket.getaddress 'localhost' #=> "::1"
-
# IPSocket.getaddress 'broadcasthost' #=> "255.255.255.255"
-
# IPSocket.getaddress 'www.ruby-lang.org' #=> "221.186.184.68"
-
# IPSocket.getaddress 'www.ccc.de' #=> "2a00:1328:e102:ccc0::122"
-
def getaddress(s)
-
if valid?(s)
-
s
-
elsif /\A[-A-Za-z\d.]+\Z/ =~ s
-
getaddress_orig(s)
-
else
-
raise ArgumentError, "invalid address"
-
end
-
end
-
end
-
end
-
-
# IPAddr provides a set of methods to manipulate an IP address. Both IPv4 and
-
# IPv6 are supported.
-
#
-
# == Example
-
#
-
# require 'ipaddr'
-
#
-
# ipaddr1 = IPAddr.new "3ffe:505:2::1"
-
#
-
# p ipaddr1 #=> #<IPAddr: IPv6:3ffe:0505:0002:0000:0000:0000:0000:0001/ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff>
-
#
-
# p ipaddr1.to_s #=> "3ffe:505:2::1"
-
#
-
# ipaddr2 = ipaddr1.mask(48) #=> #<IPAddr: IPv6:3ffe:0505:0002:0000:0000:0000:0000:0000/ffff:ffff:ffff:0000:0000:0000:0000:0000>
-
#
-
# p ipaddr2.to_s #=> "3ffe:505:2::"
-
#
-
# ipaddr3 = IPAddr.new "192.168.2.0/24"
-
#
-
# p ipaddr3 #=> #<IPAddr: IPv4:192.168.2.0/255.255.255.0>
-
-
1
class IPAddr
-
-
# 32 bit mask for IPv4
-
1
IN4MASK = 0xffffffff
-
# 128 bit mask for IPv4
-
1
IN6MASK = 0xffffffffffffffffffffffffffffffff
-
# Formatstring for IPv6
-
1
IN6FORMAT = (["%.4x"] * 8).join(':')
-
-
# Returns the address family of this IP address.
-
1
attr_reader :family
-
-
# Creates a new ipaddr containing the given network byte ordered
-
# string form of an IP address.
-
1
def IPAddr::new_ntoh(addr)
-
return IPAddr.new(IPAddr::ntop(addr))
-
end
-
-
# Convert a network byte ordered string form of an IP address into
-
# human readable form.
-
1
def IPAddr::ntop(addr)
-
case addr.size
-
when 4
-
s = addr.unpack('C4').join('.')
-
when 16
-
s = IN6FORMAT % addr.unpack('n8')
-
else
-
raise ArgumentError, "unsupported address family"
-
end
-
return s
-
end
-
-
# Returns a new ipaddr built by bitwise AND.
-
1
def &(other)
-
return self.clone.set(@addr & coerce_other(other).to_i)
-
end
-
-
# Returns a new ipaddr built by bitwise OR.
-
1
def |(other)
-
return self.clone.set(@addr | coerce_other(other).to_i)
-
end
-
-
# Returns a new ipaddr built by bitwise right-shift.
-
1
def >>(num)
-
return self.clone.set(@addr >> num)
-
end
-
-
# Returns a new ipaddr built by bitwise left shift.
-
1
def <<(num)
-
return self.clone.set(addr_mask(@addr << num))
-
end
-
-
# Returns a new ipaddr built by bitwise negation.
-
1
def ~
-
return self.clone.set(addr_mask(~@addr))
-
end
-
-
# Returns true if two ipaddrs are equal.
-
1
def ==(other)
-
8
other = coerce_other(other)
-
8
return @family == other.family && @addr == other.to_i
-
end
-
-
# Returns a new ipaddr built by masking IP address with the given
-
# prefixlen/netmask. (e.g. 8, 64, "255.255.255.0", etc.)
-
1
def mask(prefixlen)
-
return self.clone.mask!(prefixlen)
-
end
-
-
# Returns true if the given ipaddr is in the range.
-
#
-
# e.g.:
-
# require 'ipaddr'
-
# net1 = IPAddr.new("192.168.2.0/24")
-
# net2 = IPAddr.new("192.168.2.100")
-
# net3 = IPAddr.new("192.168.3.0")
-
# p net1.include?(net2) #=> true
-
# p net1.include?(net3) #=> false
-
1
def include?(other)
-
other = coerce_other(other)
-
if ipv4_mapped?
-
if (@mask_addr >> 32) != 0xffffffffffffffffffffffff
-
return false
-
end
-
mask_addr = (@mask_addr & IN4MASK)
-
addr = (@addr & IN4MASK)
-
family = Socket::AF_INET
-
else
-
mask_addr = @mask_addr
-
addr = @addr
-
family = @family
-
end
-
if other.ipv4_mapped?
-
other_addr = (other.to_i & IN4MASK)
-
other_family = Socket::AF_INET
-
else
-
other_addr = other.to_i
-
other_family = other.family
-
end
-
-
if family != other_family
-
return false
-
end
-
return ((addr & mask_addr) == (other_addr & mask_addr))
-
end
-
1
alias === include?
-
-
# Returns the integer representation of the ipaddr.
-
1
def to_i
-
8
return @addr
-
end
-
-
# Returns a string containing the IP address representation.
-
1
def to_s
-
4
str = to_string
-
4
return str if ipv4?
-
-
str.gsub!(/\b0{1,3}([\da-f]+)\b/i, '\1')
-
loop do
-
break if str.sub!(/\A0:0:0:0:0:0:0:0\Z/, '::')
-
break if str.sub!(/\b0:0:0:0:0:0:0\b/, ':')
-
break if str.sub!(/\b0:0:0:0:0:0\b/, ':')
-
break if str.sub!(/\b0:0:0:0:0\b/, ':')
-
break if str.sub!(/\b0:0:0:0\b/, ':')
-
break if str.sub!(/\b0:0:0\b/, ':')
-
break if str.sub!(/\b0:0\b/, ':')
-
break
-
end
-
str.sub!(/:{3,}/, '::')
-
-
if /\A::(ffff:)?([\da-f]{1,4}):([\da-f]{1,4})\Z/i =~ str
-
str = sprintf('::%s%d.%d.%d.%d', $1, $2.hex / 256, $2.hex % 256, $3.hex / 256, $3.hex % 256)
-
end
-
-
str
-
end
-
-
# Returns a string containing the IP address representation in
-
# canonical form.
-
1
def to_string
-
4
return _to_string(@addr)
-
end
-
-
# Returns a network byte ordered string form of the IP address.
-
1
def hton
-
case @family
-
when Socket::AF_INET
-
return [@addr].pack('N')
-
when Socket::AF_INET6
-
return (0..7).map { |i|
-
(@addr >> (112 - 16 * i)) & 0xffff
-
}.pack('n8')
-
else
-
raise "unsupported address family"
-
end
-
end
-
-
# Returns true if the ipaddr is an IPv4 address.
-
1
def ipv4?
-
4
return @family == Socket::AF_INET
-
end
-
-
# Returns true if the ipaddr is an IPv6 address.
-
1
def ipv6?
-
return @family == Socket::AF_INET6
-
end
-
-
# Returns true if the ipaddr is an IPv4-mapped IPv6 address.
-
1
def ipv4_mapped?
-
return ipv6? && (@addr >> 32) == 0xffff
-
end
-
-
# Returns true if the ipaddr is an IPv4-compatible IPv6 address.
-
1
def ipv4_compat?
-
if !ipv6? || (@addr >> 32) != 0
-
return false
-
end
-
a = (@addr & IN4MASK)
-
return a != 0 && a != 1
-
end
-
-
# Returns a new ipaddr built by converting the native IPv4 address
-
# into an IPv4-mapped IPv6 address.
-
1
def ipv4_mapped
-
if !ipv4?
-
raise ArgumentError, "not an IPv4 address"
-
end
-
return self.clone.set(@addr | 0xffff00000000, Socket::AF_INET6)
-
end
-
-
# Returns a new ipaddr built by converting the native IPv4 address
-
# into an IPv4-compatible IPv6 address.
-
1
def ipv4_compat
-
if !ipv4?
-
raise ArgumentError, "not an IPv4 address"
-
end
-
return self.clone.set(@addr, Socket::AF_INET6)
-
end
-
-
# Returns a new ipaddr built by converting the IPv6 address into a
-
# native IPv4 address. If the IP address is not an IPv4-mapped or
-
# IPv4-compatible IPv6 address, returns self.
-
1
def native
-
if !ipv4_mapped? && !ipv4_compat?
-
return self
-
end
-
return self.clone.set(@addr & IN4MASK, Socket::AF_INET)
-
end
-
-
# Returns a string for DNS reverse lookup. It returns a string in
-
# RFC3172 form for an IPv6 address.
-
1
def reverse
-
case @family
-
when Socket::AF_INET
-
return _reverse + ".in-addr.arpa"
-
when Socket::AF_INET6
-
return ip6_arpa
-
else
-
raise "unsupported address family"
-
end
-
end
-
-
# Returns a string for DNS reverse lookup compatible with RFC3172.
-
1
def ip6_arpa
-
if !ipv6?
-
raise ArgumentError, "not an IPv6 address"
-
end
-
return _reverse + ".ip6.arpa"
-
end
-
-
# Returns a string for DNS reverse lookup compatible with RFC1886.
-
1
def ip6_int
-
if !ipv6?
-
raise ArgumentError, "not an IPv6 address"
-
end
-
return _reverse + ".ip6.int"
-
end
-
-
# Returns the successor to the ipaddr.
-
1
def succ
-
return self.clone.set(@addr + 1, @family)
-
end
-
-
# Compares the ipaddr with another.
-
1
def <=>(other)
-
other = coerce_other(other)
-
-
return nil if other.family != @family
-
-
return @addr <=> other.to_i
-
end
-
1
include Comparable
-
-
# Checks equality used by Hash.
-
1
def eql?(other)
-
return self.class == other.class && self.hash == other.hash && self == other
-
end
-
-
# Returns a hash value used by Hash, Set, and Array classes
-
1
def hash
-
return ([@addr, @mask_addr].hash << 1) | (ipv4? ? 0 : 1)
-
end
-
-
# Creates a Range object for the network address.
-
1
def to_range
-
begin_addr = (@addr & @mask_addr)
-
-
case @family
-
when Socket::AF_INET
-
end_addr = (@addr | (IN4MASK ^ @mask_addr))
-
when Socket::AF_INET6
-
end_addr = (@addr | (IN6MASK ^ @mask_addr))
-
else
-
raise "unsupported address family"
-
end
-
-
return clone.set(begin_addr, @family)..clone.set(end_addr, @family)
-
end
-
-
# Returns a string containing a human-readable representation of the
-
# ipaddr. ("#<IPAddr: family:address/mask>")
-
1
def inspect
-
case @family
-
when Socket::AF_INET
-
af = "IPv4"
-
when Socket::AF_INET6
-
af = "IPv6"
-
else
-
raise "unsupported address family"
-
end
-
return sprintf("#<%s: %s:%s/%s>", self.class.name,
-
af, _to_string(@addr), _to_string(@mask_addr))
-
end
-
-
1
protected
-
-
# Set +@addr+, the internal stored ip address, to given +addr+. The
-
# parameter +addr+ is validated using the first +family+ member,
-
# which is +Socket::AF_INET+ or +Socket::AF_INET6+.
-
1
def set(addr, *family)
-
case family[0] ? family[0] : @family
-
when Socket::AF_INET
-
if addr < 0 || addr > IN4MASK
-
raise ArgumentError, "invalid address"
-
end
-
when Socket::AF_INET6
-
if addr < 0 || addr > IN6MASK
-
raise ArgumentError, "invalid address"
-
end
-
else
-
raise ArgumentError, "unsupported address family"
-
end
-
@addr = addr
-
if family[0]
-
@family = family[0]
-
end
-
return self
-
end
-
-
# Set current netmask to given mask.
-
1
def mask!(mask)
-
14
if mask.kind_of?(String)
-
14
if mask =~ /^\d+$/
-
14
prefixlen = mask.to_i
-
else
-
m = IPAddr.new(mask)
-
if m.family != @family
-
raise ArgumentError, "address family is not same"
-
end
-
@mask_addr = m.to_i
-
@addr &= @mask_addr
-
return self
-
end
-
else
-
prefixlen = mask
-
end
-
14
case @family
-
when Socket::AF_INET
-
14
if prefixlen < 0 || prefixlen > 32
-
raise ArgumentError, "invalid length"
-
end
-
14
masklen = 32 - prefixlen
-
14
@mask_addr = ((IN4MASK >> masklen) << masklen)
-
when Socket::AF_INET6
-
if prefixlen < 0 || prefixlen > 128
-
raise ArgumentError, "invalid length"
-
end
-
masklen = 128 - prefixlen
-
@mask_addr = ((IN6MASK >> masklen) << masklen)
-
else
-
raise "unsupported address family"
-
end
-
14
@addr = ((@addr >> masklen) << masklen)
-
14
return self
-
end
-
-
1
private
-
-
# Creates a new ipaddr object either from a human readable IP
-
# address representation in string, or from a packed in_addr value
-
# followed by an address family.
-
#
-
# In the former case, the following are the valid formats that will
-
# be recognized: "address", "address/prefixlen" and "address/mask",
-
# where IPv6 address may be enclosed in square brackets (`[' and
-
# `]'). If a prefixlen or a mask is specified, it returns a masked
-
# IP address. Although the address family is determined
-
# automatically from a specified string, you can specify one
-
# explicitly by the optional second argument.
-
#
-
# Otherwise an IP address is generated from a packed in_addr value
-
# and an address family.
-
#
-
# The IPAddr class defines many methods and operators, and some of
-
# those, such as &, |, include? and ==, accept a string, or a packed
-
# in_addr value instead of an IPAddr object.
-
1
def initialize(addr = '::', family = Socket::AF_UNSPEC)
-
18
if !addr.kind_of?(String)
-
case family
-
when Socket::AF_INET, Socket::AF_INET6
-
set(addr.to_i, family)
-
@mask_addr = (family == Socket::AF_INET) ? IN4MASK : IN6MASK
-
return
-
when Socket::AF_UNSPEC
-
raise ArgumentError, "address family must be specified"
-
else
-
raise ArgumentError, "unsupported address family: #{family}"
-
end
-
end
-
18
prefix, prefixlen = addr.split('/')
-
18
if prefix =~ /^\[(.*)\]$/i
-
prefix = $1
-
family = Socket::AF_INET6
-
end
-
# It seems AI_NUMERICHOST doesn't do the job.
-
#Socket.getaddrinfo(left, nil, Socket::AF_INET6, Socket::SOCK_STREAM, nil,
-
# Socket::AI_NUMERICHOST)
-
18
begin
-
18
IPSocket.getaddress(prefix) # test if address is valid
-
rescue
-
raise ArgumentError, "invalid address"
-
end
-
18
@addr = @family = nil
-
18
if family == Socket::AF_UNSPEC || family == Socket::AF_INET
-
18
@addr = in_addr(prefix)
-
18
if @addr
-
18
@family = Socket::AF_INET
-
end
-
end
-
18
if !@addr && (family == Socket::AF_UNSPEC || family == Socket::AF_INET6)
-
@addr = in6_addr(prefix)
-
@family = Socket::AF_INET6
-
end
-
18
if family != Socket::AF_UNSPEC && @family != family
-
raise ArgumentError, "address family mismatch"
-
end
-
18
if prefixlen
-
14
mask!(prefixlen)
-
else
-
4
@mask_addr = (@family == Socket::AF_INET) ? IN4MASK : IN6MASK
-
end
-
end
-
-
1
def coerce_other(other)
-
8
case other
-
when IPAddr
-
4
other
-
when String
-
4
self.class.new(other)
-
else
-
self.class.new(other, @family)
-
end
-
end
-
-
1
def in_addr(addr)
-
18
if addr =~ /^\d+\.\d+\.\d+\.\d+$/
-
return addr.split('.').inject(0) { |i, s|
-
72
i << 8 | s.to_i
-
18
}
-
end
-
return nil
-
end
-
-
1
def in6_addr(left)
-
case left
-
when /^::ffff:(\d+\.\d+\.\d+\.\d+)$/i
-
return in_addr($1) + 0xffff00000000
-
when /^::(\d+\.\d+\.\d+\.\d+)$/i
-
return in_addr($1)
-
when /[^0-9a-f:]/i
-
raise ArgumentError, "invalid address"
-
when /^(.*)::(.*)$/
-
left, right = $1, $2
-
else
-
right = ''
-
end
-
l = left.split(':')
-
r = right.split(':')
-
rest = 8 - l.size - r.size
-
if rest < 0
-
return nil
-
end
-
return (l + Array.new(rest, '0') + r).inject(0) { |i, s|
-
i << 16 | s.hex
-
}
-
end
-
-
1
def addr_mask(addr)
-
case @family
-
when Socket::AF_INET
-
return addr & IN4MASK
-
when Socket::AF_INET6
-
return addr & IN6MASK
-
else
-
raise "unsupported address family"
-
end
-
end
-
-
1
def _reverse
-
case @family
-
when Socket::AF_INET
-
return (0..3).map { |i|
-
(@addr >> (8 * i)) & 0xff
-
}.join('.')
-
when Socket::AF_INET6
-
return ("%.32x" % @addr).reverse!.gsub!(/.(?!$)/, '\&.')
-
else
-
raise "unsupported address family"
-
end
-
end
-
-
1
def _to_string(addr)
-
4
case @family
-
when Socket::AF_INET
-
4
return (0..3).map { |i|
-
16
(addr >> (24 - 8 * i)) & 0xff
-
}.join('.')
-
when Socket::AF_INET6
-
return (("%.32x" % addr).gsub!(/.{4}(?!$)/, '\&:'))
-
else
-
raise "unsupported address family"
-
end
-
end
-
-
end
-
-
1
if $0 == __FILE__
-
eval DATA.read, nil, $0, __LINE__+4
-
end
-
-
__END__
-
-
require 'test/unit'
-
-
class TC_IPAddr < Test::Unit::TestCase
-
def test_s_new
-
assert_nothing_raised {
-
IPAddr.new("3FFE:505:ffff::/48")
-
IPAddr.new("0:0:0:1::")
-
IPAddr.new("2001:200:300::/48")
-
}
-
-
a = IPAddr.new
-
assert_equal("::", a.to_s)
-
assert_equal("0000:0000:0000:0000:0000:0000:0000:0000", a.to_string)
-
assert_equal(Socket::AF_INET6, a.family)
-
-
a = IPAddr.new("0123:4567:89ab:cdef:0ABC:DEF0:1234:5678")
-
assert_equal("123:4567:89ab:cdef:abc:def0:1234:5678", a.to_s)
-
assert_equal("0123:4567:89ab:cdef:0abc:def0:1234:5678", a.to_string)
-
assert_equal(Socket::AF_INET6, a.family)
-
-
a = IPAddr.new("3ffe:505:2::/48")
-
assert_equal("3ffe:505:2::", a.to_s)
-
assert_equal("3ffe:0505:0002:0000:0000:0000:0000:0000", a.to_string)
-
assert_equal(Socket::AF_INET6, a.family)
-
assert_equal(false, a.ipv4?)
-
assert_equal(true, a.ipv6?)
-
assert_equal("#<IPAddr: IPv6:3ffe:0505:0002:0000:0000:0000:0000:0000/ffff:ffff:ffff:0000:0000:0000:0000:0000>", a.inspect)
-
-
a = IPAddr.new("3ffe:505:2::/ffff:ffff:ffff::")
-
assert_equal("3ffe:505:2::", a.to_s)
-
assert_equal("3ffe:0505:0002:0000:0000:0000:0000:0000", a.to_string)
-
assert_equal(Socket::AF_INET6, a.family)
-
-
a = IPAddr.new("0.0.0.0")
-
assert_equal("0.0.0.0", a.to_s)
-
assert_equal("0.0.0.0", a.to_string)
-
assert_equal(Socket::AF_INET, a.family)
-
-
a = IPAddr.new("192.168.1.2")
-
assert_equal("192.168.1.2", a.to_s)
-
assert_equal("192.168.1.2", a.to_string)
-
assert_equal(Socket::AF_INET, a.family)
-
assert_equal(true, a.ipv4?)
-
assert_equal(false, a.ipv6?)
-
-
a = IPAddr.new("192.168.1.2/24")
-
assert_equal("192.168.1.0", a.to_s)
-
assert_equal("192.168.1.0", a.to_string)
-
assert_equal(Socket::AF_INET, a.family)
-
assert_equal("#<IPAddr: IPv4:192.168.1.0/255.255.255.0>", a.inspect)
-
-
a = IPAddr.new("192.168.1.2/255.255.255.0")
-
assert_equal("192.168.1.0", a.to_s)
-
assert_equal("192.168.1.0", a.to_string)
-
assert_equal(Socket::AF_INET, a.family)
-
-
assert_equal("0:0:0:1::", IPAddr.new("0:0:0:1::").to_s)
-
assert_equal("2001:200:300::", IPAddr.new("2001:200:300::/48").to_s)
-
-
assert_equal("2001:200:300::", IPAddr.new("[2001:200:300::]/48").to_s)
-
-
[
-
["fe80::1%fxp0"],
-
["::1/255.255.255.0"],
-
["::1:192.168.1.2/120"],
-
[IPAddr.new("::1").to_i],
-
["::ffff:192.168.1.2/120", Socket::AF_INET],
-
["[192.168.1.2]/120"],
-
].each { |args|
-
assert_raises(ArgumentError) {
-
IPAddr.new(*args)
-
}
-
}
-
end
-
-
def test_s_new_ntoh
-
addr = ''
-
IPAddr.new("1234:5678:9abc:def0:1234:5678:9abc:def0").hton.each_byte { |c|
-
addr += sprintf("%02x", c)
-
}
-
assert_equal("123456789abcdef0123456789abcdef0", addr)
-
addr = ''
-
IPAddr.new("123.45.67.89").hton.each_byte { |c|
-
addr += sprintf("%02x", c)
-
}
-
assert_equal(sprintf("%02x%02x%02x%02x", 123, 45, 67, 89), addr)
-
a = IPAddr.new("3ffe:505:2::")
-
assert_equal("3ffe:505:2::", IPAddr.new_ntoh(a.hton).to_s)
-
a = IPAddr.new("192.168.2.1")
-
assert_equal("192.168.2.1", IPAddr.new_ntoh(a.hton).to_s)
-
end
-
-
def test_ipv4_compat
-
a = IPAddr.new("::192.168.1.2")
-
assert_equal("::192.168.1.2", a.to_s)
-
assert_equal("0000:0000:0000:0000:0000:0000:c0a8:0102", a.to_string)
-
assert_equal(Socket::AF_INET6, a.family)
-
assert_equal(true, a.ipv4_compat?)
-
b = a.native
-
assert_equal("192.168.1.2", b.to_s)
-
assert_equal(Socket::AF_INET, b.family)
-
assert_equal(false, b.ipv4_compat?)
-
-
a = IPAddr.new("192.168.1.2")
-
b = a.ipv4_compat
-
assert_equal("::192.168.1.2", b.to_s)
-
assert_equal(Socket::AF_INET6, b.family)
-
end
-
-
def test_ipv4_mapped
-
a = IPAddr.new("::ffff:192.168.1.2")
-
assert_equal("::ffff:192.168.1.2", a.to_s)
-
assert_equal("0000:0000:0000:0000:0000:ffff:c0a8:0102", a.to_string)
-
assert_equal(Socket::AF_INET6, a.family)
-
assert_equal(true, a.ipv4_mapped?)
-
b = a.native
-
assert_equal("192.168.1.2", b.to_s)
-
assert_equal(Socket::AF_INET, b.family)
-
assert_equal(false, b.ipv4_mapped?)
-
-
a = IPAddr.new("192.168.1.2")
-
b = a.ipv4_mapped
-
assert_equal("::ffff:192.168.1.2", b.to_s)
-
assert_equal(Socket::AF_INET6, b.family)
-
end
-
-
def test_reverse
-
assert_equal("f.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.2.0.0.0.5.0.5.0.e.f.f.3.ip6.arpa", IPAddr.new("3ffe:505:2::f").reverse)
-
assert_equal("1.2.168.192.in-addr.arpa", IPAddr.new("192.168.2.1").reverse)
-
end
-
-
def test_ip6_arpa
-
assert_equal("f.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.2.0.0.0.5.0.5.0.e.f.f.3.ip6.arpa", IPAddr.new("3ffe:505:2::f").ip6_arpa)
-
assert_raises(ArgumentError) {
-
IPAddr.new("192.168.2.1").ip6_arpa
-
}
-
end
-
-
def test_ip6_int
-
assert_equal("f.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.2.0.0.0.5.0.5.0.e.f.f.3.ip6.int", IPAddr.new("3ffe:505:2::f").ip6_int)
-
assert_raises(ArgumentError) {
-
IPAddr.new("192.168.2.1").ip6_int
-
}
-
end
-
-
def test_to_s
-
assert_equal("3ffe:0505:0002:0000:0000:0000:0000:0001", IPAddr.new("3ffe:505:2::1").to_string)
-
assert_equal("3ffe:505:2::1", IPAddr.new("3ffe:505:2::1").to_s)
-
end
-
end
-
-
class TC_Operator < Test::Unit::TestCase
-
-
IN6MASK32 = "ffff:ffff::"
-
IN6MASK128 = "ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff"
-
-
def setup
-
@in6_addr_any = IPAddr.new()
-
@a = IPAddr.new("3ffe:505:2::/48")
-
@b = IPAddr.new("0:0:0:1::")
-
@c = IPAddr.new(IN6MASK32)
-
end
-
alias set_up setup
-
-
def test_or
-
assert_equal("3ffe:505:2:1::", (@a | @b).to_s)
-
a = @a
-
a |= @b
-
assert_equal("3ffe:505:2:1::", a.to_s)
-
assert_equal("3ffe:505:2::", @a.to_s)
-
assert_equal("3ffe:505:2:1::",
-
(@a | 0x00000000000000010000000000000000).to_s)
-
end
-
-
def test_and
-
assert_equal("3ffe:505::", (@a & @c).to_s)
-
a = @a
-
a &= @c
-
assert_equal("3ffe:505::", a.to_s)
-
assert_equal("3ffe:505:2::", @a.to_s)
-
assert_equal("3ffe:505::", (@a & 0xffffffff000000000000000000000000).to_s)
-
end
-
-
def test_shift_right
-
assert_equal("0:3ffe:505:2::", (@a >> 16).to_s)
-
a = @a
-
a >>= 16
-
assert_equal("0:3ffe:505:2::", a.to_s)
-
assert_equal("3ffe:505:2::", @a.to_s)
-
end
-
-
def test_shift_left
-
assert_equal("505:2::", (@a << 16).to_s)
-
a = @a
-
a <<= 16
-
assert_equal("505:2::", a.to_s)
-
assert_equal("3ffe:505:2::", @a.to_s)
-
end
-
-
def test_carrot
-
a = ~@in6_addr_any
-
assert_equal(IN6MASK128, a.to_s)
-
assert_equal("::", @in6_addr_any.to_s)
-
end
-
-
def test_equal
-
assert_equal(true, @a == IPAddr.new("3ffe:505:2::"))
-
assert_equal(false, @a == IPAddr.new("3ffe:505:3::"))
-
assert_equal(true, @a != IPAddr.new("3ffe:505:3::"))
-
assert_equal(false, @a != IPAddr.new("3ffe:505:2::"))
-
end
-
-
def test_mask
-
a = @a.mask(32)
-
assert_equal("3ffe:505::", a.to_s)
-
assert_equal("3ffe:505:2::", @a.to_s)
-
end
-
-
def test_include?
-
assert_equal(true, @a.include?(IPAddr.new("3ffe:505:2::")))
-
assert_equal(true, @a.include?(IPAddr.new("3ffe:505:2::1")))
-
assert_equal(false, @a.include?(IPAddr.new("3ffe:505:3::")))
-
net1 = IPAddr.new("192.168.2.0/24")
-
assert_equal(true, net1.include?(IPAddr.new("192.168.2.0")))
-
assert_equal(true, net1.include?(IPAddr.new("192.168.2.255")))
-
assert_equal(false, net1.include?(IPAddr.new("192.168.3.0")))
-
# test with integer parameter
-
int = (192 << 24) + (168 << 16) + (2 << 8) + 13
-
-
assert_equal(true, net1.include?(int))
-
assert_equal(false, net1.include?(int+255))
-
-
end
-
-
def test_hash
-
a1 = IPAddr.new('192.168.2.0')
-
a2 = IPAddr.new('192.168.2.0')
-
a3 = IPAddr.new('3ffe:505:2::1')
-
a4 = IPAddr.new('3ffe:505:2::1')
-
a5 = IPAddr.new('127.0.0.1')
-
a6 = IPAddr.new('::1')
-
a7 = IPAddr.new('192.168.2.0/25')
-
a8 = IPAddr.new('192.168.2.0/25')
-
-
h = { a1 => 'ipv4', a2 => 'ipv4', a3 => 'ipv6', a4 => 'ipv6', a5 => 'ipv4', a6 => 'ipv6', a7 => 'ipv4', a8 => 'ipv4'}
-
assert_equal(5, h.size)
-
assert_equal('ipv4', h[a1])
-
assert_equal('ipv4', h[a2])
-
assert_equal('ipv6', h[a3])
-
assert_equal('ipv6', h[a4])
-
-
require 'set'
-
s = Set[a1, a2, a3, a4, a5, a6, a7, a8]
-
assert_equal(5, s.size)
-
assert_equal(true, s.include?(a1))
-
assert_equal(true, s.include?(a2))
-
assert_equal(true, s.include?(a3))
-
assert_equal(true, s.include?(a4))
-
assert_equal(true, s.include?(a5))
-
assert_equal(true, s.include?(a6))
-
end
-
end
-
# logger.rb - simple logging utility
-
# Copyright (C) 2000-2003, 2005, 2008, 2011 NAKAMURA, Hiroshi <nahi@ruby-lang.org>.
-
#
-
# Documentation:: NAKAMURA, Hiroshi and Gavin Sinclair
-
# License::
-
# You can redistribute it and/or modify it under the same terms of Ruby's
-
# license; either the dual license version in 2003, or any later version.
-
# Revision:: $Id: logger.rb 31641 2011-05-19 00:07:25Z nobu $
-
#
-
# A simple system for logging messages. See Logger for more documentation.
-
-
1
require 'monitor'
-
-
# == Description
-
#
-
# The Logger class provides a simple but sophisticated logging utility that
-
# you can use to output messages.
-
#
-
# The messages have associated levels, such as +INFO+ or +ERROR+ that indicate
-
# their importance. You can then give the Logger a level, and only messages
-
# at that level of higher will be printed.
-
#
-
# The levels are:
-
#
-
# +FATAL+:: an unhandleable error that results in a program crash
-
# +ERROR+:: a handleable error condition
-
# +WARN+:: a warning
-
# +INFO+:: generic (useful) information about system operation
-
# +DEBUG+:: low-level information for developers
-
#
-
# For instance, in a production system, you may have your Logger set to
-
# +INFO+ or even +WARN+
-
# When you are developing the system, however, you probably
-
# want to know about the program's internal state, and would set the Logger to
-
# +DEBUG+.
-
#
-
# *Note*: Logger does not escape or sanitize any messages passed to it.
-
# Developers should be aware of when potentially malicious data (user-input)
-
# is passed to Logger, and manually escape the untrusted data:
-
#
-
# logger.info("User-input: #{input.dump}")
-
# logger.info("User-input: %p" % input)
-
#
-
# You can use #formatter= for escaping all data.
-
#
-
# original_formatter = Logger::Formatter.new
-
# logger.formatter = proc { |severity, datetime, progname, msg|
-
# original_formatter.call(severity, datetime, progname, msg.dump)
-
# }
-
# logger.info(input)
-
#
-
# === Example
-
#
-
# This creates a logger to the standard output stream, with a level of +WARN+
-
#
-
# log = Logger.new(STDOUT)
-
# log.level = Logger::WARN
-
#
-
# log.debug("Created logger")
-
# log.info("Program started")
-
# log.warn("Nothing to do!")
-
#
-
# begin
-
# File.each_line(path) do |line|
-
# unless line =~ /^(\w+) = (.*)$/
-
# log.error("Line in wrong format: #{line}")
-
# end
-
# end
-
# rescue => err
-
# log.fatal("Caught exception; exiting")
-
# log.fatal(err)
-
# end
-
#
-
# Because the Logger's level is set to +WARN+, only the warning, error, and
-
# fatal messages are recorded. The debug and info messages are silently
-
# discarded.
-
#
-
# === Features
-
#
-
# There are several interesting features that Logger provides, like
-
# auto-rolling of log files, setting the format of log messages, and
-
# specifying a program name in conjunction with the message. The next section
-
# shows you how to achieve these things.
-
#
-
#
-
# == HOWTOs
-
#
-
# === How to create a logger
-
#
-
# The options below give you various choices, in more or less increasing
-
# complexity.
-
#
-
# 1. Create a logger which logs messages to STDERR/STDOUT.
-
#
-
# logger = Logger.new(STDERR)
-
# logger = Logger.new(STDOUT)
-
#
-
# 2. Create a logger for the file which has the specified name.
-
#
-
# logger = Logger.new('logfile.log')
-
#
-
# 3. Create a logger for the specified file.
-
#
-
# file = File.open('foo.log', File::WRONLY | File::APPEND)
-
# # To create new (and to remove old) logfile, add File::CREAT like;
-
# # file = open('foo.log', File::WRONLY | File::APPEND | File::CREAT)
-
# logger = Logger.new(file)
-
#
-
# 4. Create a logger which ages logfile once it reaches a certain size. Leave
-
# 10 "old log files" and each file is about 1,024,000 bytes.
-
#
-
# logger = Logger.new('foo.log', 10, 1024000)
-
#
-
# 5. Create a logger which ages logfile daily/weekly/monthly.
-
#
-
# logger = Logger.new('foo.log', 'daily')
-
# logger = Logger.new('foo.log', 'weekly')
-
# logger = Logger.new('foo.log', 'monthly')
-
#
-
# === How to log a message
-
#
-
# Notice the different methods (+fatal+, +error+, +info+) being used to log
-
# messages of various levels? Other methods in this family are +warn+ and
-
# +debug+. +add+ is used below to log a message of an arbitrary (perhaps
-
# dynamic) level.
-
#
-
# 1. Message in block.
-
#
-
# logger.fatal { "Argument 'foo' not given." }
-
#
-
# 2. Message as a string.
-
#
-
# logger.error "Argument #{ @foo } mismatch."
-
#
-
# 3. With progname.
-
#
-
# logger.info('initialize') { "Initializing..." }
-
#
-
# 4. With severity.
-
#
-
# logger.add(Logger::FATAL) { 'Fatal error!' }
-
#
-
# The block form allows you to create potentially complex log messages,
-
# but to delay their evaluation until and unless the message is
-
# logged. For example, if we have the following:
-
#
-
# logger.debug { "This is a " + potentially + " expensive operation" }
-
#
-
# If the logger's level is +INFO+ or higher, no debug messages will be logged,
-
# and the entire block will not even be evaluated. Compare to this:
-
#
-
# logger.debug("This is a " + potentially + " expensive operation")
-
#
-
# Here, the string concatenation is done every time, even if the log
-
# level is not set to show the debug message.
-
#
-
# === How to close a logger
-
#
-
# logger.close
-
#
-
# === Setting severity threshold
-
#
-
# 1. Original interface.
-
#
-
# logger.sev_threshold = Logger::WARN
-
#
-
# 2. Log4r (somewhat) compatible interface.
-
#
-
# logger.level = Logger::INFO
-
#
-
# DEBUG < INFO < WARN < ERROR < FATAL < UNKNOWN
-
#
-
#
-
# == Format
-
#
-
# Log messages are rendered in the output stream in a certain format by
-
# default. The default format and a sample are shown below:
-
#
-
# Log format:
-
# SeverityID, [Date Time mSec #pid] SeverityLabel -- ProgName: message
-
#
-
# Log sample:
-
# I, [Wed Mar 03 02:34:24 JST 1999 895701 #19074] INFO -- Main: info.
-
#
-
# You may change the date and time format via #datetime_format=
-
#
-
# logger.datetime_format = "%Y-%m-%d %H:%M:%S"
-
# # e.g. "2004-01-03 00:54:26"
-
#
-
# Or, you may change the overall format with #formatter= method.
-
#
-
# logger.formatter = proc do |severity, datetime, progname, msg|
-
# "#{datetime}: #{msg}\n"
-
# end
-
# # e.g. "Thu Sep 22 08:51:08 GMT+9:00 2005: hello world"
-
#
-
1
class Logger
-
1
VERSION = "1.2.7"
-
1
_, name, rev = %w$Id: logger.rb 31641 2011-05-19 00:07:25Z nobu $
-
1
if name
-
1
name = name.chomp(",v")
-
else
-
name = File.basename(__FILE__)
-
end
-
1
rev ||= "v#{VERSION}"
-
1
ProgName = "#{name}/#{rev}"
-
-
1
class Error < RuntimeError # :nodoc:
-
end
-
# not used after 1.2.7. just for compat.
-
1
class ShiftingError < Error # :nodoc:
-
end
-
-
# Logging severity.
-
1
module Severity
-
# Low-level information, mostly for developers
-
1
DEBUG = 0
-
# generic, useful information about system operation
-
1
INFO = 1
-
# a warning
-
1
WARN = 2
-
# a handleable error condition
-
1
ERROR = 3
-
# an unhandleable error that results in a program crash
-
1
FATAL = 4
-
# an unknown message that should always be logged
-
1
UNKNOWN = 5
-
end
-
1
include Severity
-
-
# Logging severity threshold (e.g. <tt>Logger::INFO</tt>).
-
1
attr_accessor :level
-
-
# program name to include in log messages.
-
1
attr_accessor :progname
-
-
# Set date-time format.
-
#
-
# +datetime_format+:: A string suitable for passing to +strftime+.
-
1
def datetime_format=(datetime_format)
-
@default_formatter.datetime_format = datetime_format
-
end
-
-
# Returns the date format being used. See #datetime_format=
-
1
def datetime_format
-
@default_formatter.datetime_format
-
end
-
-
# Logging formatter, as a +Proc+ that will take four arguments and
-
# return the formatted message. The arguments are:
-
#
-
# +severity+:: The Severity of the log message
-
# +time+:: A Time instance representing when the message was logged
-
# +progname+:: The #progname configured, or passed to the logger method
-
# +msg+:: The _Object_ the user passed to the log message; not necessarily a
-
# String.
-
#
-
# The block should return an Object that can be written to the logging
-
# device via +write+. The default formatter is used when no formatter is
-
# set.
-
1
attr_accessor :formatter
-
-
1
alias sev_threshold level
-
1
alias sev_threshold= level=
-
-
# Returns +true+ iff the current severity level allows for the printing of
-
# +DEBUG+ messages.
-
67835
def debug?; @level <= DEBUG; end
-
-
# Returns +true+ iff the current severity level allows for the printing of
-
# +INFO+ messages.
-
1
def info?; @level <= INFO; end
-
-
# Returns +true+ iff the current severity level allows for the printing of
-
# +WARN+ messages.
-
1
def warn?; @level <= WARN; end
-
-
# Returns +true+ iff the current severity level allows for the printing of
-
# +ERROR+ messages.
-
1
def error?; @level <= ERROR; end
-
-
# Returns +true+ iff the current severity level allows for the printing of
-
# +FATAL+ messages.
-
1
def fatal?; @level <= FATAL; end
-
-
#
-
# === Synopsis
-
#
-
# Logger.new(name, shift_age = 7, shift_size = 1048576)
-
# Logger.new(name, shift_age = 'weekly')
-
#
-
# === Args
-
#
-
# +logdev+::
-
# The log device. This is a filename (String) or IO object (typically
-
# +STDOUT+, +STDERR+, or an open file).
-
# +shift_age+::
-
# Number of old log files to keep, *or* frequency of rotation (+daily+,
-
# +weekly+ or +monthly+).
-
# +shift_size+::
-
# Maximum logfile size (only applies when +shift_age+ is a number).
-
#
-
# === Description
-
#
-
# Create an instance.
-
#
-
1
def initialize(logdev, shift_age = 0, shift_size = 1048576)
-
5
@progname = nil
-
5
@level = DEBUG
-
5
@default_formatter = Formatter.new
-
5
@formatter = nil
-
5
@logdev = nil
-
5
if logdev
-
5
@logdev = LogDevice.new(logdev, :shift_age => shift_age,
-
:shift_size => shift_size)
-
end
-
end
-
-
#
-
# === Synopsis
-
#
-
# Logger#add(severity, message = nil, progname = nil) { ... }
-
#
-
# === Args
-
#
-
# +severity+::
-
# Severity. Constants are defined in Logger namespace: +DEBUG+, +INFO+,
-
# +WARN+, +ERROR+, +FATAL+, or +UNKNOWN+.
-
# +message+::
-
# The log message. A String or Exception.
-
# +progname+::
-
# Program name string. Can be omitted. Treated as a message if no
-
# +message+ and +block+ are given.
-
# +block+::
-
# Can be omitted. Called to get a message string if +message+ is nil.
-
#
-
# === Return
-
#
-
# +true+ if successful, +false+ otherwise.
-
#
-
# When the given severity is not high enough (for this particular logger), log
-
# no message, and return +true+.
-
#
-
# === Description
-
#
-
# Log a message if the given severity is high enough. This is the generic
-
# logging method. Users will be more inclined to use #debug, #info, #warn,
-
# #error, and #fatal.
-
#
-
# <b>Message format</b>: +message+ can be any object, but it has to be
-
# converted to a String in order to log it. Generally, +inspect+ is used
-
# if the given object is not a String.
-
# A special case is an +Exception+ object, which will be printed in detail,
-
# including message, class, and backtrace. See #msg2str for the
-
# implementation if required.
-
#
-
# === Bugs
-
#
-
# * Logfile is not locked.
-
# * Append open does not need to lock file.
-
# * If the OS which supports multi I/O, records possibly be mixed.
-
#
-
1
def add(severity, message = nil, progname = nil, &block)
-
47183
severity ||= UNKNOWN
-
47183
if @logdev.nil? or severity < @level
-
500
return true
-
end
-
46683
progname ||= @progname
-
46683
if message.nil?
-
46683
if block_given?
-
message = yield
-
else
-
46683
message = progname
-
46683
progname = @progname
-
end
-
end
-
46683
@logdev.write(
-
format_message(format_severity(severity), Time.now, progname, message))
-
46683
true
-
end
-
1
alias log add
-
-
#
-
# Dump given message to the log device without any formatting. If no log
-
# device exists, return +nil+.
-
#
-
1
def <<(msg)
-
unless @logdev.nil?
-
@logdev.write(msg)
-
end
-
end
-
-
#
-
# Log a +DEBUG+ message.
-
#
-
# See #info for more information.
-
#
-
1
def debug(progname = nil, &block)
-
46165
add(DEBUG, nil, progname, &block)
-
end
-
-
#
-
# :call-seq:
-
# info(message)
-
# info(progname,&block)
-
#
-
# Log an +INFO+ message.
-
#
-
# +message+:: the message to log; does not need to be a String
-
# +progname+:: in the block form, this is the #progname to use in the
-
# the log message. The default can be set with #progname=
-
# <tt>&block</tt>:: evaluates to the message to log. This is not evaluated
-
# unless the logger's level is sufficient
-
# to log the message. This allows you to create
-
# potentially expensive logging messages that are
-
# only called when the logger is configured to show them.
-
#
-
# === Examples
-
#
-
# logger.info("MainApp") { "Received connection from #{ip}" }
-
# # ...
-
# logger.info "Waiting for input from user"
-
# # ...
-
# logger.info { "User typed #{input}" }
-
#
-
# You'll probably stick to the second form above, unless you want to provide a
-
# program name (which you can do with #progname= as well).
-
#
-
# === Return
-
#
-
# See #add.
-
#
-
1
def info(progname = nil, &block)
-
61
add(INFO, nil, progname, &block)
-
end
-
-
#
-
# Log a +WARN+ message.
-
#
-
# See #info for more information.
-
#
-
1
def warn(progname = nil, &block)
-
504
add(WARN, nil, progname, &block)
-
end
-
-
#
-
# Log an +ERROR+ message.
-
#
-
# See #info for more information.
-
#
-
1
def error(progname = nil, &block)
-
453
add(ERROR, nil, progname, &block)
-
end
-
-
#
-
# Log a +FATAL+ message.
-
#
-
# See #info for more information.
-
#
-
1
def fatal(progname = nil, &block)
-
add(FATAL, nil, progname, &block)
-
end
-
-
#
-
# Log an +UNKNOWN+ message. This will be printed no matter what the logger's
-
# level.
-
#
-
# See #info for more information.
-
#
-
1
def unknown(progname = nil, &block)
-
add(UNKNOWN, nil, progname, &block)
-
end
-
-
#
-
# Close the logging device.
-
#
-
1
def close
-
@logdev.close if @logdev
-
end
-
-
1
private
-
-
# Severity label for logging. (max 5 char)
-
1
SEV_LABEL = %w(DEBUG INFO WARN ERROR FATAL ANY)
-
-
1
def format_severity(severity)
-
46683
SEV_LABEL[severity] || 'ANY'
-
end
-
-
1
def format_message(severity, datetime, progname, msg)
-
46683
(@formatter || @default_formatter).call(severity, datetime, progname, msg)
-
end
-
-
-
# Default formatter for log messages
-
1
class Formatter
-
1
Format = "%s, [%s#%d] %5s -- %s: %s\n"
-
-
1
attr_accessor :datetime_format
-
-
1
def initialize
-
10
@datetime_format = nil
-
end
-
-
1
def call(severity, time, progname, msg)
-
Format % [severity[0..0], format_datetime(time), $$, severity, progname,
-
msg2str(msg)]
-
end
-
-
1
private
-
-
1
def format_datetime(time)
-
if @datetime_format.nil?
-
time.strftime("%Y-%m-%dT%H:%M:%S.") << "%06d " % time.usec
-
else
-
time.strftime(@datetime_format)
-
end
-
end
-
-
1
def msg2str(msg)
-
case msg
-
when ::String
-
msg
-
when ::Exception
-
"#{ msg.message } (#{ msg.class })\n" <<
-
(msg.backtrace || []).join("\n")
-
else
-
msg.inspect
-
end
-
end
-
end
-
-
-
# Device used for logging messages.
-
1
class LogDevice
-
1
attr_reader :dev
-
1
attr_reader :filename
-
-
1
class LogDeviceMutex
-
1
include MonitorMixin
-
end
-
-
1
def initialize(log = nil, opt = {})
-
5
@dev = @filename = @shift_age = @shift_size = nil
-
5
@mutex = LogDeviceMutex.new
-
5
if log.respond_to?(:write) and log.respond_to?(:close)
-
4
@dev = log
-
else
-
1
@dev = open_logfile(log)
-
1
@dev.sync = true
-
1
@filename = log
-
1
@shift_age = opt[:shift_age] || 7
-
1
@shift_size = opt[:shift_size] || 1048576
-
end
-
end
-
-
1
def write(message)
-
46683
begin
-
46683
@mutex.synchronize do
-
46683
if @shift_age and @dev.respond_to?(:stat)
-
46678
begin
-
46678
check_shift_log
-
rescue
-
warn("log shifting failed. #{$!}")
-
end
-
end
-
46683
begin
-
46683
@dev.write(message)
-
rescue
-
warn("log writing failed. #{$!}")
-
end
-
end
-
rescue Exception => ignored
-
warn("log writing failed. #{ignored}")
-
end
-
end
-
-
1
def close
-
begin
-
@mutex.synchronize do
-
@dev.close rescue nil
-
end
-
rescue Exception
-
@dev.close rescue nil
-
end
-
end
-
-
1
private
-
-
1
def open_logfile(filename)
-
1
if (FileTest.exist?(filename))
-
1
open(filename, (File::WRONLY | File::APPEND))
-
else
-
create_logfile(filename)
-
end
-
end
-
-
1
def create_logfile(filename)
-
logdev = open(filename, (File::WRONLY | File::APPEND | File::CREAT))
-
logdev.sync = true
-
add_log_header(logdev)
-
logdev
-
end
-
-
1
def add_log_header(file)
-
file.write(
-
"# Logfile created on %s by %s\n" % [Time.now.to_s, Logger::ProgName]
-
)
-
end
-
-
1
SiD = 24 * 60 * 60
-
-
1
def check_shift_log
-
46678
if @shift_age.is_a?(Integer)
-
# Note: always returns false if '0'.
-
46678
if @filename && (@shift_age > 0) && (@dev.stat.size > @shift_size)
-
shift_log_age
-
end
-
else
-
now = Time.now
-
period_end = previous_period_end(now)
-
if @dev.stat.mtime <= period_end
-
shift_log_period(period_end)
-
end
-
end
-
end
-
-
1
def shift_log_age
-
(@shift_age-3).downto(0) do |i|
-
if FileTest.exist?("#{@filename}.#{i}")
-
File.rename("#{@filename}.#{i}", "#{@filename}.#{i+1}")
-
end
-
end
-
@dev.close rescue nil
-
File.rename("#{@filename}", "#{@filename}.0")
-
@dev = create_logfile(@filename)
-
return true
-
end
-
-
1
def shift_log_period(period_end)
-
postfix = period_end.strftime("%Y%m%d") # YYYYMMDD
-
age_file = "#{@filename}.#{postfix}"
-
if FileTest.exist?(age_file)
-
# try to avoid filename crash caused by Timestamp change.
-
idx = 0
-
# .99 can be overridden; avoid too much file search with 'loop do'
-
while idx < 100
-
idx += 1
-
age_file = "#{@filename}.#{postfix}.#{idx}"
-
break unless FileTest.exist?(age_file)
-
end
-
end
-
@dev.close rescue nil
-
File.rename("#{@filename}", age_file)
-
@dev = create_logfile(@filename)
-
return true
-
end
-
-
1
def previous_period_end(now)
-
case @shift_age
-
when /^daily$/
-
eod(now - 1 * SiD)
-
when /^weekly$/
-
eod(now - ((now.wday + 1) * SiD))
-
when /^monthly$/
-
eod(now - now.mday * SiD)
-
else
-
now
-
end
-
end
-
-
1
def eod(t)
-
Time.mktime(t.year, t.month, t.mday, 23, 59, 59)
-
end
-
end
-
-
-
#
-
# == Description
-
#
-
# Application -- Add logging support to your application.
-
#
-
# == Usage
-
#
-
# 1. Define your application class as a sub-class of this class.
-
# 2. Override 'run' method in your class to do many things.
-
# 3. Instantiate it and invoke 'start'.
-
#
-
# == Example
-
#
-
# class FooApp < Application
-
# def initialize(foo_app, application_specific, arguments)
-
# super('FooApp') # Name of the application.
-
# end
-
#
-
# def run
-
# ...
-
# log(WARN, 'warning', 'my_method1')
-
# ...
-
# @log.error('my_method2') { 'Error!' }
-
# ...
-
# end
-
# end
-
#
-
# status = FooApp.new(....).start
-
#
-
1
class Application
-
1
include Logger::Severity
-
-
# Name of the application given at initialize.
-
1
attr_reader :appname
-
-
#
-
# == Synopsis
-
#
-
# Application.new(appname = '')
-
#
-
# == Args
-
#
-
# +appname+:: Name of the application.
-
#
-
# == Description
-
#
-
# Create an instance. Log device is +STDERR+ by default. This can be
-
# changed with #set_log.
-
#
-
1
def initialize(appname = nil)
-
@appname = appname
-
@log = Logger.new(STDERR)
-
@log.progname = @appname
-
@level = @log.level
-
end
-
-
#
-
# Start the application. Return the status code.
-
#
-
1
def start
-
status = -1
-
begin
-
log(INFO, "Start of #{ @appname }.")
-
status = run
-
rescue
-
log(FATAL, "Detected an exception. Stopping ... #{$!} (#{$!.class})\n" << $@.join("\n"))
-
ensure
-
log(INFO, "End of #{ @appname }. (status: #{ status.to_s })")
-
end
-
status
-
end
-
-
# Logger for this application. See the class Logger for an explanation.
-
1
def logger
-
@log
-
end
-
-
#
-
# Sets the logger for this application. See the class Logger for an
-
# explanation.
-
#
-
1
def logger=(logger)
-
@log = logger
-
@log.progname = @appname
-
@log.level = @level
-
end
-
-
#
-
# Sets the log device for this application. See <tt>Logger.new</tt> for
-
# an explanation of the arguments.
-
#
-
1
def set_log(logdev, shift_age = 0, shift_size = 1024000)
-
@log = Logger.new(logdev, shift_age, shift_size)
-
@log.progname = @appname
-
@log.level = @level
-
end
-
-
1
def log=(logdev)
-
set_log(logdev)
-
end
-
-
#
-
# Set the logging threshold, just like <tt>Logger#level=</tt>.
-
#
-
1
def level=(level)
-
@level = level
-
@log.level = @level
-
end
-
-
#
-
# See Logger#add. This application's +appname+ is used.
-
#
-
1
def log(severity, message = nil, &block)
-
@log.add(severity, message, @appname, &block) if @log
-
end
-
-
1
private
-
-
1
def run
-
# TODO: should be an NotImplementedError
-
raise RuntimeError.new('Method run must be defined in the derived class.')
-
end
-
end
-
end
-
#
-
# mutex_m.rb -
-
# $Release Version: 3.0$
-
# $Revision: 1.7 $
-
# Original from mutex.rb
-
# by Keiju ISHITSUKA(keiju@ishitsuka.com)
-
# modified by matz
-
# patched by akira yamada
-
#
-
# --
-
# Usage:
-
# require "mutex_m.rb"
-
# obj = Object.new
-
# obj.extend Mutex_m
-
# ...
-
# extended object can be handled like Mutex
-
# or
-
# class Foo
-
# include Mutex_m
-
# ...
-
# end
-
# obj = Foo.new
-
# this obj can be handled like Mutex
-
#
-
-
1
require 'thread'
-
-
1
module Mutex_m
-
1
def Mutex_m.define_aliases(cl)
-
1
cl.module_eval %q{
-
alias locked? mu_locked?
-
alias lock mu_lock
-
alias unlock mu_unlock
-
alias try_lock mu_try_lock
-
alias synchronize mu_synchronize
-
}
-
end
-
-
1
def Mutex_m.append_features(cl)
-
1
super
-
1
define_aliases(cl) unless cl.instance_of?(Module)
-
end
-
-
1
def Mutex_m.extend_object(obj)
-
super
-
obj.mu_extended
-
end
-
-
1
def mu_extended
-
unless (defined? locked? and
-
defined? lock and
-
defined? unlock and
-
defined? try_lock and
-
defined? synchronize)
-
Mutex_m.define_aliases(singleton_class)
-
end
-
mu_initialize
-
end
-
-
# locking
-
1
def mu_synchronize(&block)
-
135768
@_mutex.synchronize(&block)
-
end
-
-
1
def mu_locked?
-
@_mutex.locked?
-
end
-
-
1
def mu_try_lock
-
@_mutex.try_lock
-
end
-
-
1
def mu_lock
-
@_mutex.lock
-
end
-
-
1
def mu_unlock
-
@_mutex.unlock
-
end
-
-
1
def sleep(timeout = nil)
-
@_mutex.sleep(timeout)
-
end
-
-
1
private
-
-
1
def mu_initialize
-
8
@_mutex = Mutex.new
-
end
-
-
1
def initialize(*args)
-
8
mu_initialize
-
8
super
-
end
-
end
-
=begin
-
= $RCSfile$ -- Loader for all OpenSSL C-space and Ruby-space definitions
-
-
= Info
-
'OpenSSL for Ruby 2' project
-
Copyright (C) 2002 Michal Rokos <m.rokos@sh.cvut.cz>
-
All rights reserved.
-
-
= Licence
-
This program is licenced under the same licence as Ruby.
-
(See the file 'LICENCE'.)
-
-
= Version
-
$Id: openssl.rb 32665 2011-07-25 06:38:44Z nahi $
-
=end
-
-
1
require 'openssl.so'
-
-
1
require 'openssl/bn'
-
1
require 'openssl/cipher'
-
1
require 'openssl/config'
-
1
require 'openssl/digest'
-
1
require 'openssl/ssl-internal'
-
1
require 'openssl/x509-internal'
-
-
#--
-
#
-
# $RCSfile$
-
#
-
# = Ruby-space definitions that completes C-space funcs for BN
-
#
-
# = Info
-
# 'OpenSSL for Ruby 2' project
-
# Copyright (C) 2002 Michal Rokos <m.rokos@sh.cvut.cz>
-
# All rights reserved.
-
#
-
# = Licence
-
# This program is licenced under the same licence as Ruby.
-
# (See the file 'LICENCE'.)
-
#
-
# = Version
-
# $Id: bn.rb 33067 2011-08-25 00:52:10Z drbrain $
-
#
-
#++
-
-
1
module OpenSSL
-
1
class BN
-
1
include Comparable
-
end # BN
-
end # OpenSSL
-
-
##
-
# Add double dispatch to Integer
-
#
-
1
class Integer
-
1
def to_bn
-
OpenSSL::BN::new(self.to_s(16), 16)
-
end
-
end # Integer
-
-
=begin
-
= $RCSfile$ -- Buffering mix-in module.
-
-
= Info
-
'OpenSSL for Ruby 2' project
-
Copyright (C) 2001 GOTOU YUUZOU <gotoyuzo@notwork.org>
-
All rights reserved.
-
-
= Licence
-
This program is licenced under the same licence as Ruby.
-
(See the file 'LICENCE'.)
-
-
= Version
-
$Id: buffering.rb 32012 2011-06-11 14:07:42Z nahi $
-
=end
-
-
##
-
# OpenSSL IO buffering mix-in module.
-
#
-
# This module allows an OpenSSL::SSL::SSLSocket to behave like an IO.
-
-
1
module OpenSSL::Buffering
-
1
include Enumerable
-
-
##
-
# The "sync mode" of the SSLSocket.
-
#
-
# See IO#sync for full details.
-
-
1
attr_accessor :sync
-
-
##
-
# Default size to read from or write to the SSLSocket for buffer operations.
-
-
1
BLOCK_SIZE = 1024*16
-
-
1
def initialize(*args)
-
@eof = false
-
@rbuffer = ""
-
@sync = @io.sync
-
end
-
-
#
-
# for reading.
-
#
-
1
private
-
-
##
-
# Fills the buffer from the underlying SSLSocket
-
-
1
def fill_rbuff
-
begin
-
@rbuffer << self.sysread(BLOCK_SIZE)
-
rescue Errno::EAGAIN
-
retry
-
rescue EOFError
-
@eof = true
-
end
-
end
-
-
##
-
# Consumes +size+ bytes from the buffer
-
-
1
def consume_rbuff(size=nil)
-
if @rbuffer.empty?
-
nil
-
else
-
size = @rbuffer.size unless size
-
ret = @rbuffer[0, size]
-
@rbuffer[0, size] = ""
-
ret
-
end
-
end
-
-
1
public
-
-
##
-
# Reads +size+ bytes from the stream. If +buf+ is provided it must
-
# reference a string which will receive the data.
-
#
-
# See IO#read for full details.
-
-
1
def read(size=nil, buf=nil)
-
if size == 0
-
if buf
-
buf.clear
-
return buf
-
else
-
return ""
-
end
-
end
-
until @eof
-
break if size && size <= @rbuffer.size
-
fill_rbuff
-
end
-
ret = consume_rbuff(size) || ""
-
if buf
-
buf.replace(ret)
-
ret = buf
-
end
-
(size && ret.empty?) ? nil : ret
-
end
-
-
##
-
# Reads at most +maxlen+ bytes from the stream. If +buf+ is provided it
-
# must reference a string which will receive the data.
-
#
-
# See IO#readpartial for full details.
-
-
1
def readpartial(maxlen, buf=nil)
-
if maxlen == 0
-
if buf
-
buf.clear
-
return buf
-
else
-
return ""
-
end
-
end
-
if @rbuffer.empty?
-
begin
-
return sysread(maxlen, buf)
-
rescue Errno::EAGAIN
-
retry
-
end
-
end
-
ret = consume_rbuff(maxlen)
-
if buf
-
buf.replace(ret)
-
ret = buf
-
end
-
raise EOFError if ret.empty?
-
ret
-
end
-
-
##
-
# Reads at most +maxlen+ bytes in the non-blocking manner.
-
#
-
# When no data can be read without blocking it raises
-
# OpenSSL::SSL::SSLError extended by IO::WaitReadable or IO::WaitWritable.
-
#
-
# IO::WaitReadable means SSL needs to read internally so read_nonblock
-
# should be called again when the underlying IO is readable.
-
#
-
# IO::WaitWritable means SSL needs to write internally so read_nonblock
-
# should be called again after the underlying IO is writable.
-
#
-
# OpenSSL::Buffering#read_nonblock needs two rescue clause as follows:
-
#
-
# # emulates blocking read (readpartial).
-
# begin
-
# result = ssl.read_nonblock(maxlen)
-
# rescue IO::WaitReadable
-
# IO.select([io])
-
# retry
-
# rescue IO::WaitWritable
-
# IO.select(nil, [io])
-
# retry
-
# end
-
#
-
# Note that one reason that read_nonblock writes to the underlying IO is
-
# when the peer requests a new TLS/SSL handshake. See openssl the FAQ for
-
# more details. http://www.openssl.org/support/faq.html
-
-
1
def read_nonblock(maxlen, buf=nil)
-
if maxlen == 0
-
if buf
-
buf.clear
-
return buf
-
else
-
return ""
-
end
-
end
-
if @rbuffer.empty?
-
return sysread_nonblock(maxlen, buf)
-
end
-
ret = consume_rbuff(maxlen)
-
if buf
-
buf.replace(ret)
-
ret = buf
-
end
-
raise EOFError if ret.empty?
-
ret
-
end
-
-
##
-
# Reads the next "line+ from the stream. Lines are separated by +eol+. If
-
# +limit+ is provided the result will not be longer than the given number of
-
# bytes.
-
#
-
# +eol+ may be a String or Regexp.
-
#
-
# Unlike IO#gets the line read will not be assigned to +$_+.
-
#
-
# Unlike IO#gets the separator must be provided if a limit is provided.
-
-
1
def gets(eol=$/, limit=nil)
-
idx = @rbuffer.index(eol)
-
until @eof
-
break if idx
-
fill_rbuff
-
idx = @rbuffer.index(eol)
-
end
-
if eol.is_a?(Regexp)
-
size = idx ? idx+$&.size : nil
-
else
-
size = idx ? idx+eol.size : nil
-
end
-
if limit and limit >= 0
-
size = [size, limit].min
-
end
-
consume_rbuff(size)
-
end
-
-
##
-
# Executes the block for every line in the stream where lines are separated
-
# by +eol+.
-
#
-
# See also #gets
-
-
1
def each(eol=$/)
-
while line = self.gets(eol)
-
yield line
-
end
-
end
-
1
alias each_line each
-
-
##
-
# Reads lines from the stream which are separated by +eol+.
-
#
-
# See also #gets
-
-
1
def readlines(eol=$/)
-
ary = []
-
while line = self.gets(eol)
-
ary << line
-
end
-
ary
-
end
-
-
##
-
# Reads a line from the stream which is separated by +eol+.
-
#
-
# Raises EOFError if at end of file.
-
-
1
def readline(eol=$/)
-
raise EOFError if eof?
-
gets(eol)
-
end
-
-
##
-
# Reads one character from the stream. Returns nil if called at end of
-
# file.
-
-
1
def getc
-
read(1)
-
end
-
-
##
-
# Calls the given block once for each byte in the stream.
-
-
1
def each_byte # :yields: byte
-
while c = getc
-
yield(c.ord)
-
end
-
end
-
-
##
-
# Reads a one-character string from the stream. Raises an EOFError at end
-
# of file.
-
-
1
def readchar
-
raise EOFError if eof?
-
getc
-
end
-
-
##
-
# Pushes character +c+ back onto the stream such that a subsequent buffered
-
# character read will return it.
-
#
-
# Unlike IO#getc multiple bytes may be pushed back onto the stream.
-
#
-
# Has no effect on unbuffered reads (such as #sysread).
-
-
1
def ungetc(c)
-
@rbuffer[0,0] = c.chr
-
end
-
-
##
-
# Returns true if the stream is at file which means there is no more data to
-
# be read.
-
-
1
def eof?
-
fill_rbuff if !@eof && @rbuffer.empty?
-
@eof && @rbuffer.empty?
-
end
-
1
alias eof eof?
-
-
#
-
# for writing.
-
#
-
1
private
-
-
##
-
# Writes +s+ to the buffer. When the buffer is full or #sync is true the
-
# buffer is flushed to the underlying socket.
-
-
1
def do_write(s)
-
@wbuffer = "" unless defined? @wbuffer
-
@wbuffer << s
-
@sync ||= false
-
if @sync or @wbuffer.size > BLOCK_SIZE or idx = @wbuffer.rindex($/)
-
remain = idx ? idx + $/.size : @wbuffer.length
-
nwritten = 0
-
while remain > 0
-
str = @wbuffer[nwritten,remain]
-
begin
-
nwrote = syswrite(str)
-
rescue Errno::EAGAIN
-
retry
-
end
-
remain -= nwrote
-
nwritten += nwrote
-
end
-
@wbuffer[0,nwritten] = ""
-
end
-
end
-
-
1
public
-
-
##
-
# Writes +s+ to the stream. If the argument is not a string it will be
-
# converted using String#to_s. Returns the number of bytes written.
-
-
1
def write(s)
-
do_write(s)
-
s.length
-
end
-
-
##
-
# Writes +str+ in the non-blocking manner.
-
#
-
# If there is buffered data, it is flushed first. This may block.
-
#
-
# write_nonblock returns number of bytes written to the SSL connection.
-
#
-
# When no data can be written without blocking it raises
-
# OpenSSL::SSL::SSLError extended by IO::WaitReadable or IO::WaitWritable.
-
#
-
# IO::WaitReadable means SSL needs to read internally so write_nonblock
-
# should be called again after the underlying IO is readable.
-
#
-
# IO::WaitWritable means SSL needs to write internally so write_nonblock
-
# should be called again after underlying IO is writable.
-
#
-
# So OpenSSL::Buffering#write_nonblock needs two rescue clause as follows.
-
#
-
# # emulates blocking write.
-
# begin
-
# result = ssl.write_nonblock(str)
-
# rescue IO::WaitReadable
-
# IO.select([io])
-
# retry
-
# rescue IO::WaitWritable
-
# IO.select(nil, [io])
-
# retry
-
# end
-
#
-
# Note that one reason that write_nonblock reads from the underlying IO
-
# is when the peer requests a new TLS/SSL handshake. See the openssl FAQ
-
# for more details. http://www.openssl.org/support/faq.html
-
-
1
def write_nonblock(s)
-
flush
-
syswrite_nonblock(s)
-
end
-
-
##
-
# Writes +s+ to the stream. +s+ will be converted to a String using
-
# String#to_s.
-
-
1
def << (s)
-
do_write(s)
-
self
-
end
-
-
##
-
# Writes +args+ to the stream along with a record separator.
-
#
-
# See IO#puts for full details.
-
-
1
def puts(*args)
-
s = ""
-
if args.empty?
-
s << "\n"
-
end
-
args.each{|arg|
-
s << arg.to_s
-
if $/ && /\n\z/ !~ s
-
s << "\n"
-
end
-
}
-
do_write(s)
-
nil
-
end
-
-
##
-
# Writes +args+ to the stream.
-
#
-
# See IO#print for full details.
-
-
1
def print(*args)
-
s = ""
-
args.each{ |arg| s << arg.to_s }
-
do_write(s)
-
nil
-
end
-
-
##
-
# Formats and writes to the stream converting parameters under control of
-
# the format string.
-
#
-
# See Kernel#sprintf for format string details.
-
-
1
def printf(s, *args)
-
do_write(s % args)
-
nil
-
end
-
-
##
-
# Flushes buffered data to the SSLSocket.
-
-
1
def flush
-
osync = @sync
-
@sync = true
-
do_write ""
-
return self
-
ensure
-
@sync = osync
-
end
-
-
##
-
# Closes the SSLSocket and flushes any unwritten data.
-
-
1
def close
-
flush rescue nil
-
sysclose
-
end
-
end
-
#--
-
#
-
# $RCSfile$
-
#
-
# = Ruby-space predefined Cipher subclasses
-
#
-
# = Info
-
# 'OpenSSL for Ruby 2' project
-
# Copyright (C) 2002 Michal Rokos <m.rokos@sh.cvut.cz>
-
# All rights reserved.
-
#
-
# = Licence
-
# This program is licenced under the same licence as Ruby.
-
# (See the file 'LICENCE'.)
-
#
-
# = Version
-
# $Id: cipher.rb 33067 2011-08-25 00:52:10Z drbrain $
-
#
-
#++
-
-
1
module OpenSSL
-
1
class Cipher
-
1
%w(AES CAST5 BF DES IDEA RC2 RC4 RC5).each{|name|
-
8
klass = Class.new(Cipher){
-
8
define_method(:initialize){|*args|
-
cipher_name = args.inject(name){|n, arg| "#{n}-#{arg}" }
-
super(cipher_name)
-
}
-
}
-
8
const_set(name, klass)
-
}
-
-
1
%w(128 192 256).each{|keylen|
-
3
klass = Class.new(Cipher){
-
3
define_method(:initialize){|mode|
-
mode ||= "CBC"
-
cipher_name = "AES-#{keylen}-#{mode}"
-
super(cipher_name)
-
}
-
}
-
3
const_set("AES#{keylen}", klass)
-
}
-
-
# Generate, set, and return a random key.
-
# You must call cipher.encrypt or cipher.decrypt before calling this method.
-
1
def random_key
-
str = OpenSSL::Random.random_bytes(self.key_len)
-
self.key = str
-
return str
-
end
-
-
# Generate, set, and return a random iv.
-
# You must call cipher.encrypt or cipher.decrypt before calling this method.
-
1
def random_iv
-
str = OpenSSL::Random.random_bytes(self.iv_len)
-
self.iv = str
-
return str
-
end
-
-
# This class is only provided for backwards compatibility. Use OpenSSL::Cipher in the future.
-
1
class Cipher < Cipher
-
# add warning
-
end
-
end # Cipher
-
end # OpenSSL
-
=begin
-
= Ruby-space definitions that completes C-space funcs for Config
-
-
= Info
-
Copyright (C) 2010 Hiroshi Nakamura <nahi@ruby-lang.org>
-
-
= Licence
-
This program is licenced under the same licence as Ruby.
-
(See the file 'LICENCE'.)
-
-
=end
-
-
1
require 'stringio'
-
-
1
module OpenSSL
-
1
class Config
-
1
include Enumerable
-
-
1
class << self
-
1
def parse(str)
-
c = new()
-
parse_config(StringIO.new(str)).each do |section, hash|
-
c[section] = hash
-
end
-
c
-
end
-
-
1
alias load new
-
-
1
def parse_config(io)
-
begin
-
parse_config_lines(io)
-
rescue ConfigError => e
-
e.message.replace("error in line #{io.lineno}: " + e.message)
-
raise
-
end
-
end
-
-
1
def get_key_string(data, section, key) # :nodoc:
-
if v = data[section] && data[section][key]
-
return v
-
elsif section == 'ENV'
-
if v = ENV[key]
-
return v
-
end
-
end
-
if v = data['default'] && data['default'][key]
-
return v
-
end
-
end
-
-
1
private
-
-
1
def parse_config_lines(io)
-
section = 'default'
-
data = {section => {}}
-
while definition = get_definition(io)
-
definition = clear_comments(definition)
-
next if definition.empty?
-
if definition[0] == ?[
-
if /\[([^\]]*)\]/ =~ definition
-
section = $1.strip
-
data[section] ||= {}
-
else
-
raise ConfigError, "missing close square bracket"
-
end
-
else
-
if /\A([^:\s]*)(?:::([^:\s]*))?\s*=(.*)\z/ =~ definition
-
if $2
-
section = $1
-
key = $2
-
else
-
key = $1
-
end
-
value = unescape_value(data, section, $3)
-
(data[section] ||= {})[key] = value.strip
-
else
-
raise ConfigError, "missing equal sign"
-
end
-
end
-
end
-
data
-
end
-
-
# escape with backslash
-
1
QUOTE_REGEXP_SQ = /\A([^'\\]*(?:\\.[^'\\]*)*)'/
-
# escape with backslash and doubled dq
-
1
QUOTE_REGEXP_DQ = /\A([^"\\]*(?:""[^"\\]*|\\.[^"\\]*)*)"/
-
# escaped char map
-
1
ESCAPE_MAP = {
-
"r" => "\r",
-
"n" => "\n",
-
"b" => "\b",
-
"t" => "\t",
-
}
-
-
1
def unescape_value(data, section, value)
-
scanned = []
-
while m = value.match(/['"\\$]/)
-
scanned << m.pre_match
-
c = m[0]
-
value = m.post_match
-
case c
-
when "'"
-
if m = value.match(QUOTE_REGEXP_SQ)
-
scanned << m[1].gsub(/\\(.)/, '\\1')
-
value = m.post_match
-
else
-
break
-
end
-
when '"'
-
if m = value.match(QUOTE_REGEXP_DQ)
-
scanned << m[1].gsub(/""/, '').gsub(/\\(.)/, '\\1')
-
value = m.post_match
-
else
-
break
-
end
-
when "\\"
-
c = value.slice!(0, 1)
-
scanned << (ESCAPE_MAP[c] || c)
-
when "$"
-
ref, value = extract_reference(value)
-
refsec = section
-
if ref.index('::')
-
refsec, ref = ref.split('::', 2)
-
end
-
if v = get_key_string(data, refsec, ref)
-
scanned << v
-
else
-
raise ConfigError, "variable has no value"
-
end
-
else
-
raise 'must not reaced'
-
end
-
end
-
scanned << value
-
scanned.join
-
end
-
-
1
def extract_reference(value)
-
rest = ''
-
if m = value.match(/\(([^)]*)\)|\{([^}]*)\}/)
-
value = m[1] || m[2]
-
rest = m.post_match
-
elsif [?(, ?{].include?(value[0])
-
raise ConfigError, "no close brace"
-
end
-
if m = value.match(/[a-zA-Z0-9_]*(?:::[a-zA-Z0-9_]*)?/)
-
return m[0], m.post_match + rest
-
else
-
raise
-
end
-
end
-
-
1
def clear_comments(line)
-
# FCOMMENT
-
if m = line.match(/\A([\t\n\f ]*);.*\z/)
-
return m[1]
-
end
-
# COMMENT
-
scanned = []
-
while m = line.match(/[#'"\\]/)
-
scanned << m.pre_match
-
c = m[0]
-
line = m.post_match
-
case c
-
when '#'
-
line = nil
-
break
-
when "'", '"'
-
regexp = (c == "'") ? QUOTE_REGEXP_SQ : QUOTE_REGEXP_DQ
-
scanned << c
-
if m = line.match(regexp)
-
scanned << m[0]
-
line = m.post_match
-
else
-
scanned << line
-
line = nil
-
break
-
end
-
when "\\"
-
scanned << c
-
scanned << line.slice!(0, 1)
-
else
-
raise 'must not reaced'
-
end
-
end
-
scanned << line
-
scanned.join
-
end
-
-
1
def get_definition(io)
-
if line = get_line(io)
-
while /[^\\]\\\z/ =~ line
-
if extra = get_line(io)
-
line += extra
-
else
-
break
-
end
-
end
-
return line.strip
-
end
-
end
-
-
1
def get_line(io)
-
if line = io.gets
-
line.gsub(/[\r\n]*/, '')
-
end
-
end
-
end
-
-
1
def initialize(filename = nil)
-
@data = {}
-
if filename
-
File.open(filename.to_s) do |file|
-
Config.parse_config(file).each do |section, hash|
-
self[section] = hash
-
end
-
end
-
end
-
end
-
-
1
def get_value(section, key)
-
if section.nil?
-
raise TypeError.new('nil not allowed')
-
end
-
section = 'default' if section.empty?
-
get_key_string(section, key)
-
end
-
-
1
def value(arg1, arg2 = nil)
-
warn('Config#value is deprecated; use Config#get_value')
-
if arg2.nil?
-
section, key = 'default', arg1
-
else
-
section, key = arg1, arg2
-
end
-
section ||= 'default'
-
section = 'default' if section.empty?
-
get_key_string(section, key)
-
end
-
-
1
def add_value(section, key, value)
-
check_modify
-
(@data[section] ||= {})[key] = value
-
end
-
-
1
def [](section)
-
@data[section] || {}
-
end
-
-
1
def section(name)
-
warn('Config#section is deprecated; use Config#[]')
-
@data[name] || {}
-
end
-
-
1
def []=(section, pairs)
-
check_modify
-
@data[section] ||= {}
-
pairs.each do |key, value|
-
self.add_value(section, key, value)
-
end
-
end
-
-
1
def sections
-
@data.keys
-
end
-
-
1
def to_s
-
ary = []
-
@data.keys.sort.each do |section|
-
ary << "[ #{section} ]\n"
-
@data[section].keys.each do |key|
-
ary << "#{key}=#{@data[section][key]}\n"
-
end
-
ary << "\n"
-
end
-
ary.join
-
end
-
-
1
def each
-
@data.each do |section, hash|
-
hash.each do |key, value|
-
yield [section, key, value]
-
end
-
end
-
end
-
-
1
def inspect
-
"#<#{self.class.name} sections=#{sections.inspect}>"
-
end
-
-
1
protected
-
-
1
def data
-
@data
-
end
-
-
1
private
-
-
1
def initialize_copy(other)
-
@data = other.data.dup
-
end
-
-
1
def check_modify
-
raise TypeError.new("Insecure: can't modify OpenSSL config") if frozen?
-
end
-
-
1
def get_key_string(section, key)
-
Config.get_key_string(@data, section, key)
-
end
-
end
-
end
-
#--
-
#
-
# $RCSfile$
-
#
-
# = Ruby-space predefined Digest subclasses
-
#
-
# = Info
-
# 'OpenSSL for Ruby 2' project
-
# Copyright (C) 2002 Michal Rokos <m.rokos@sh.cvut.cz>
-
# All rights reserved.
-
#
-
# = Licence
-
# This program is licenced under the same licence as Ruby.
-
# (See the file 'LICENCE'.)
-
#
-
# = Version
-
# $Id: digest.rb 33067 2011-08-25 00:52:10Z drbrain $
-
#
-
#++
-
-
1
module OpenSSL
-
1
class Digest
-
-
1
alg = %w(DSS DSS1 MD2 MD4 MD5 MDC2 RIPEMD160 SHA SHA1)
-
1
if OPENSSL_VERSION_NUMBER > 0x00908000
-
1
alg += %w(SHA224 SHA256 SHA384 SHA512)
-
end
-
-
# Return the +data+ hash computed with +name+ Digest. +name+ is either the
-
# long name or short name of a supported digest algorithm.
-
#
-
# === Examples
-
#
-
# OpenSSL::Digest.digest("SHA256, "abc")
-
#
-
# which is equivalent to:
-
#
-
# OpenSSL::Digest::SHA256.digest("abc")
-
-
1
def self.digest(name, data)
-
super(data, name)
-
end
-
-
1
alg.each{|name|
-
13
klass = Class.new(Digest){
-
13
define_method(:initialize){|*data|
-
if data.length > 1
-
raise ArgumentError,
-
"wrong number of arguments (#{data.length} for 1)"
-
end
-
super(name, data.first)
-
}
-
}
-
26
singleton = (class << klass; self; end)
-
13
singleton.class_eval{
-
13
define_method(:digest){|data| Digest.digest(name, data) }
-
13
define_method(:hexdigest){|data| Digest.hexdigest(name, data) }
-
}
-
13
const_set(name, klass)
-
}
-
-
# This class is only provided for backwards compatibility. Use OpenSSL::Digest in the future.
-
1
class Digest < Digest
-
1
def initialize(*args)
-
# add warning
-
super(*args)
-
end
-
end
-
-
end # Digest
-
end # OpenSSL
-
-
=begin
-
= $RCSfile$ -- Ruby-space definitions that completes C-space funcs for SSL
-
-
= Info
-
'OpenSSL for Ruby 2' project
-
Copyright (C) 2001 GOTOU YUUZOU <gotoyuzo@notwork.org>
-
All rights reserved.
-
-
= Licence
-
This program is licenced under the same licence as Ruby.
-
(See the file 'LICENCE'.)
-
-
= Version
-
$Id: ssl-internal.rb 29189 2010-09-06 01:53:00Z nahi $
-
=end
-
-
1
require "openssl/buffering"
-
1
require "fcntl"
-
-
1
module OpenSSL
-
1
module SSL
-
1
class SSLContext
-
1
DEFAULT_PARAMS = {
-
:ssl_version => "SSLv23",
-
:verify_mode => OpenSSL::SSL::VERIFY_PEER,
-
:ciphers => "ALL:!ADH:!EXPORT:!SSLv2:RC4+RSA:+HIGH:+MEDIUM:+LOW",
-
:options => OpenSSL::SSL::OP_ALL,
-
}
-
-
1
DEFAULT_CERT_STORE = OpenSSL::X509::Store.new
-
1
DEFAULT_CERT_STORE.set_default_paths
-
1
if defined?(OpenSSL::X509::V_FLAG_CRL_CHECK_ALL)
-
1
DEFAULT_CERT_STORE.flags = OpenSSL::X509::V_FLAG_CRL_CHECK_ALL
-
end
-
-
1
def set_params(params={})
-
params = DEFAULT_PARAMS.merge(params)
-
params.each{|name, value| self.__send__("#{name}=", value) }
-
if self.verify_mode != OpenSSL::SSL::VERIFY_NONE
-
unless self.ca_file or self.ca_path or self.cert_store
-
self.cert_store = DEFAULT_CERT_STORE
-
end
-
end
-
return params
-
end
-
end
-
-
1
module SocketForwarder
-
1
def addr
-
to_io.addr
-
end
-
-
1
def peeraddr
-
to_io.peeraddr
-
end
-
-
1
def setsockopt(level, optname, optval)
-
to_io.setsockopt(level, optname, optval)
-
end
-
-
1
def getsockopt(level, optname)
-
to_io.getsockopt(level, optname)
-
end
-
-
1
def fcntl(*args)
-
to_io.fcntl(*args)
-
end
-
-
1
def closed?
-
to_io.closed?
-
end
-
-
1
def do_not_reverse_lookup=(flag)
-
to_io.do_not_reverse_lookup = flag
-
end
-
end
-
-
1
module Nonblock
-
1
def initialize(*args)
-
flag = File::NONBLOCK
-
flag |= @io.fcntl(Fcntl::F_GETFL) if defined?(Fcntl::F_GETFL)
-
@io.fcntl(Fcntl::F_SETFL, flag)
-
super
-
end
-
end
-
-
1
def verify_certificate_identity(cert, hostname)
-
should_verify_common_name = true
-
cert.extensions.each{|ext|
-
next if ext.oid != "subjectAltName"
-
ext.value.split(/,\s+/).each{|general_name|
-
if /\ADNS:(.*)/ =~ general_name
-
should_verify_common_name = false
-
reg = Regexp.escape($1).gsub(/\\\*/, "[^.]+")
-
return true if /\A#{reg}\z/i =~ hostname
-
elsif /\AIP Address:(.*)/ =~ general_name
-
should_verify_common_name = false
-
return true if $1 == hostname
-
end
-
}
-
}
-
if should_verify_common_name
-
cert.subject.to_a.each{|oid, value|
-
if oid == "CN"
-
reg = Regexp.escape(value).gsub(/\\\*/, "[^.]+")
-
return true if /\A#{reg}\z/i =~ hostname
-
end
-
}
-
end
-
return false
-
end
-
1
module_function :verify_certificate_identity
-
-
1
class SSLSocket
-
1
include Buffering
-
1
include SocketForwarder
-
1
include Nonblock
-
-
1
def post_connection_check(hostname)
-
unless OpenSSL::SSL.verify_certificate_identity(peer_cert, hostname)
-
raise SSLError, "hostname does not match the server certificate"
-
end
-
return true
-
end
-
-
1
def session
-
SSL::Session.new(self)
-
rescue SSL::Session::SessionError
-
nil
-
end
-
end
-
-
1
class SSLServer
-
1
include SocketForwarder
-
1
attr_accessor :start_immediately
-
-
1
def initialize(svr, ctx)
-
@svr = svr
-
@ctx = ctx
-
unless ctx.session_id_context
-
session_id = OpenSSL::Digest::MD5.hexdigest($0)
-
@ctx.session_id_context = session_id
-
end
-
@start_immediately = true
-
end
-
-
1
def to_io
-
@svr
-
end
-
-
1
def listen(backlog=5)
-
@svr.listen(backlog)
-
end
-
-
1
def shutdown(how=Socket::SHUT_RDWR)
-
@svr.shutdown(how)
-
end
-
-
1
def accept
-
sock = @svr.accept
-
begin
-
ssl = OpenSSL::SSL::SSLSocket.new(sock, @ctx)
-
ssl.sync_close = true
-
ssl.accept if @start_immediately
-
ssl
-
rescue SSLError => ex
-
sock.close
-
raise ex
-
end
-
end
-
-
1
def close
-
@svr.close
-
end
-
end
-
end
-
end
-
=begin
-
= $RCSfile$ -- Ruby-space definitions that completes C-space funcs for X509 and subclasses
-
-
= Info
-
'OpenSSL for Ruby 2' project
-
Copyright (C) 2002 Michal Rokos <m.rokos@sh.cvut.cz>
-
All rights reserved.
-
-
= Licence
-
This program is licenced under the same licence as Ruby.
-
(See the file 'LICENCE'.)
-
-
= Version
-
$Id: x509-internal.rb 32663 2011-07-25 04:51:26Z nahi $
-
=end
-
-
1
module OpenSSL
-
1
module X509
-
1
class ExtensionFactory
-
1
def create_extension(*arg)
-
if arg.size > 1
-
create_ext(*arg)
-
else
-
send("create_ext_from_"+arg[0].class.name.downcase, arg[0])
-
end
-
end
-
-
1
def create_ext_from_array(ary)
-
raise ExtensionError, "unexpected array form" if ary.size > 3
-
create_ext(ary[0], ary[1], ary[2])
-
end
-
-
1
def create_ext_from_string(str) # "oid = critical, value"
-
oid, value = str.split(/=/, 2)
-
oid.strip!
-
value.strip!
-
create_ext(oid, value)
-
end
-
-
1
def create_ext_from_hash(hash)
-
create_ext(hash["oid"], hash["value"], hash["critical"])
-
end
-
end
-
-
1
class Extension
-
1
def to_s # "oid = critical, value"
-
str = self.oid
-
str << " = "
-
str << "critical, " if self.critical?
-
str << self.value.gsub(/\n/, ", ")
-
end
-
-
1
def to_h # {"oid"=>sn|ln, "value"=>value, "critical"=>true|false}
-
{"oid"=>self.oid,"value"=>self.value,"critical"=>self.critical?}
-
end
-
-
1
def to_a
-
[ self.oid, self.value, self.critical? ]
-
end
-
end
-
-
1
class Name
-
1
module RFC2253DN
-
1
Special = ',=+<>#;'
-
1
HexChar = /[0-9a-fA-F]/
-
1
HexPair = /#{HexChar}#{HexChar}/
-
1
HexString = /#{HexPair}+/
-
1
Pair = /\\(?:[#{Special}]|\\|"|#{HexPair})/
-
1
StringChar = /[^#{Special}\\"]/
-
1
QuoteChar = /[^\\"]/
-
1
AttributeType = /[a-zA-Z][0-9a-zA-Z]*|[0-9]+(?:\.[0-9]+)*/
-
1
AttributeValue = /
-
(?!["#])((?:#{StringChar}|#{Pair})*)|
-
\#(#{HexString})|
-
"((?:#{QuoteChar}|#{Pair})*)"
-
/x
-
1
TypeAndValue = /\A(#{AttributeType})=#{AttributeValue}/
-
-
1
module_function
-
-
1
def expand_pair(str)
-
return nil unless str
-
return str.gsub(Pair){
-
pair = $&
-
case pair.size
-
when 2 then pair[1,1]
-
when 3 then Integer("0x#{pair[1,2]}").chr
-
else raise OpenSSL::X509::NameError, "invalid pair: #{str}"
-
end
-
}
-
end
-
-
1
def expand_hexstring(str)
-
return nil unless str
-
der = str.gsub(HexPair){$&.to_i(16).chr }
-
a1 = OpenSSL::ASN1.decode(der)
-
return a1.value, a1.tag
-
end
-
-
1
def expand_value(str1, str2, str3)
-
value = expand_pair(str1)
-
value, tag = expand_hexstring(str2) unless value
-
value = expand_pair(str3) unless value
-
return value, tag
-
end
-
-
1
def scan(dn)
-
str = dn
-
ary = []
-
while true
-
if md = TypeAndValue.match(str)
-
remain = md.post_match
-
type = md[1]
-
value, tag = expand_value(md[2], md[3], md[4]) rescue nil
-
if value
-
type_and_value = [type, value]
-
type_and_value.push(tag) if tag
-
ary.unshift(type_and_value)
-
if remain.length > 2 && remain[0] == ?,
-
str = remain[1..-1]
-
next
-
elsif remain.length > 2 && remain[0] == ?+
-
raise OpenSSL::X509::NameError,
-
"multi-valued RDN is not supported: #{dn}"
-
elsif remain.empty?
-
break
-
end
-
end
-
end
-
msg_dn = dn[0, dn.length - str.length] + " =>" + str
-
raise OpenSSL::X509::NameError, "malformed RDN: #{msg_dn}"
-
end
-
return ary
-
end
-
end
-
-
1
class << self
-
1
def parse_rfc2253(str, template=OBJECT_TYPE_TEMPLATE)
-
ary = OpenSSL::X509::Name::RFC2253DN.scan(str)
-
self.new(ary, template)
-
end
-
-
1
def parse_openssl(str, template=OBJECT_TYPE_TEMPLATE)
-
ary = str.scan(/\s*([^\/,]+)\s*/).collect{|i| i[0].split("=", 2) }
-
self.new(ary, template)
-
end
-
-
1
alias parse parse_openssl
-
end
-
end
-
-
1
class StoreContext
-
1
def cleanup
-
warn "(#{caller.first}) OpenSSL::X509::StoreContext#cleanup is deprecated with no replacement" if $VERBOSE
-
end
-
end
-
end
-
end
-
#vim:ts=2 sw=2 noexpandtab:
-
1
require 'rexml/child'
-
1
require 'rexml/source'
-
-
1
module REXML
-
# This class needs:
-
# * Documentation
-
# * Work! Not all types of attlists are intelligently parsed, so we just
-
# spew back out what we get in. This works, but it would be better if
-
# we formatted the output ourselves.
-
#
-
# AttlistDecls provide *just* enough support to allow namespace
-
# declarations. If you need some sort of generalized support, or have an
-
# interesting idea about how to map the hideous, terrible design of DTD
-
# AttlistDecls onto an intuitive Ruby interface, let me know. I'm desperate
-
# for anything to make DTDs more palateable.
-
1
class AttlistDecl < Child
-
1
include Enumerable
-
-
# What is this? Got me.
-
1
attr_reader :element_name
-
-
# Create an AttlistDecl, pulling the information from a Source. Notice
-
# that this isn't very convenient; to create an AttlistDecl, you basically
-
# have to format it yourself, and then have the initializer parse it.
-
# Sorry, but for the forseeable future, DTD support in REXML is pretty
-
# weak on convenience. Have I mentioned how much I hate DTDs?
-
1
def initialize(source)
-
super()
-
if (source.kind_of? Array)
-
@element_name, @pairs, @contents = *source
-
end
-
end
-
-
# Access the attlist attribute/value pairs.
-
# value = attlist_decl[ attribute_name ]
-
1
def [](key)
-
@pairs[key]
-
end
-
-
# Whether an attlist declaration includes the given attribute definition
-
# if attlist_decl.include? "xmlns:foobar"
-
1
def include?(key)
-
@pairs.keys.include? key
-
end
-
-
# Iterate over the key/value pairs:
-
# attlist_decl.each { |attribute_name, attribute_value| ... }
-
1
def each(&block)
-
@pairs.each(&block)
-
end
-
-
# Write out exactly what we got in.
-
1
def write out, indent=-1
-
out << @contents
-
end
-
-
1
def node_type
-
:attlistdecl
-
end
-
end
-
end
-
1
require "rexml/namespace"
-
1
require 'rexml/text'
-
-
1
module REXML
-
# Defines an Element Attribute; IE, a attribute=value pair, as in:
-
# <element attribute="value"/>. Attributes can be in their own
-
# namespaces. General users of REXML will not interact with the
-
# Attribute class much.
-
1
class Attribute
-
1
include Node
-
1
include Namespace
-
-
# The element to which this attribute belongs
-
1
attr_reader :element
-
# The normalized value of this attribute. That is, the attribute with
-
# entities intact.
-
1
attr_writer :normalized
-
1
PATTERN = /\s*(#{NAME_STR})\s*=\s*(["'])(.*?)\2/um
-
-
1
NEEDS_A_SECOND_CHECK = /(<|&((#{Entity::NAME});|(#0*((?:\d+)|(?:x[a-fA-F0-9]+)));)?)/um
-
-
# Constructor.
-
# FIXME: The parser doesn't catch illegal characters in attributes
-
#
-
# first::
-
# Either: an Attribute, which this new attribute will become a
-
# clone of; or a String, which is the name of this attribute
-
# second::
-
# If +first+ is an Attribute, then this may be an Element, or nil.
-
# If nil, then the Element parent of this attribute is the parent
-
# of the +first+ Attribute. If the first argument is a String,
-
# then this must also be a String, and is the content of the attribute.
-
# If this is the content, it must be fully normalized (contain no
-
# illegal characters).
-
# parent::
-
# Ignored unless +first+ is a String; otherwise, may be the Element
-
# parent of this attribute, or nil.
-
#
-
#
-
# Attribute.new( attribute_to_clone )
-
# Attribute.new( attribute_to_clone, parent_element )
-
# Attribute.new( "attr", "attr_value" )
-
# Attribute.new( "attr", "attr_value", parent_element )
-
1
def initialize( first, second=nil, parent=nil )
-
163
@normalized = @unnormalized = @element = nil
-
163
if first.kind_of? Attribute
-
self.name = first.expanded_name
-
@unnormalized = first.value
-
if second.kind_of? Element
-
@element = second
-
else
-
@element = first.element
-
end
-
163
elsif first.kind_of? String
-
163
@element = parent
-
163
self.name = first
-
163
@normalized = second.to_s
-
else
-
raise "illegal argument #{first.class.name} to Attribute constructor"
-
end
-
end
-
-
# Returns the namespace of the attribute.
-
#
-
# e = Element.new( "elns:myelement" )
-
# e.add_attribute( "nsa:a", "aval" )
-
# e.add_attribute( "b", "bval" )
-
# e.attributes.get_attribute( "a" ).prefix # -> "nsa"
-
# e.attributes.get_attribute( "b" ).prefix # -> "elns"
-
# a = Attribute.new( "x", "y" )
-
# a.prefix # -> ""
-
1
def prefix
-
pf = super
-
if pf == ""
-
pf = @element.prefix if @element
-
end
-
pf
-
end
-
-
# Returns the namespace URL, if defined, or nil otherwise
-
#
-
# e = Element.new("el")
-
# e.add_attributes({"xmlns:ns", "http://url"})
-
# e.namespace( "ns" ) # -> "http://url"
-
1
def namespace arg=nil
-
arg = prefix if arg.nil?
-
@element.namespace arg
-
end
-
-
# Returns true if other is an Attribute and has the same name and value,
-
# false otherwise.
-
1
def ==( other )
-
other.kind_of?(Attribute) and other.name==name and other.value==value
-
end
-
-
# Creates (and returns) a hash from both the name and value
-
1
def hash
-
name.hash + value.hash
-
end
-
-
# Returns this attribute out as XML source, expanding the name
-
#
-
# a = Attribute.new( "x", "y" )
-
# a.to_string # -> "x='y'"
-
# b = Attribute.new( "ns:x", "y" )
-
# b.to_string # -> "ns:x='y'"
-
1
def to_string
-
if @element and @element.context and @element.context[:attribute_quote] == :quote
-
%Q^#@expanded_name="#{to_s().gsub(/"/, '"e;')}"^
-
else
-
"#@expanded_name='#{to_s().gsub(/'/, ''')}'"
-
end
-
end
-
-
1
def doctype
-
321
if @element
-
321
doc = @element.document
-
321
doc.doctype if doc
-
end
-
end
-
-
# Returns the attribute value, with entities replaced
-
1
def to_s
-
return @normalized if @normalized
-
-
@normalized = Text::normalize( @unnormalized, doctype )
-
@unnormalized = nil
-
@normalized
-
end
-
-
# Returns the UNNORMALIZED value of this attribute. That is, entities
-
# have been expanded to their values
-
1
def value
-
158
return @unnormalized if @unnormalized
-
158
@unnormalized = Text::unnormalize( @normalized, doctype )
-
158
@normalized = nil
-
158
@unnormalized
-
end
-
-
# Returns a copy of this attribute
-
1
def clone
-
Attribute.new self
-
end
-
-
# Sets the element of which this object is an attribute. Normally, this
-
# is not directly called.
-
#
-
# Returns this attribute
-
1
def element=( element )
-
163
@element = element
-
-
163
if @normalized
-
163
Text.check( @normalized, NEEDS_A_SECOND_CHECK, doctype )
-
end
-
-
163
self
-
end
-
-
# Removes this Attribute from the tree, and returns true if successfull
-
#
-
# This method is usually not called directly.
-
1
def remove
-
@element.attributes.delete self.name unless @element.nil?
-
end
-
-
# Writes this attribute (EG, puts 'key="value"' to the output)
-
1
def write( output, indent=-1 )
-
output << to_string
-
end
-
-
1
def node_type
-
:attribute
-
end
-
-
1
def inspect
-
rv = ""
-
write( rv )
-
rv
-
end
-
-
1
def xpath
-
path = @element.xpath
-
path += "/@#{self.expanded_name}"
-
return path
-
end
-
end
-
end
-
#vim:ts=2 sw=2 noexpandtab:
-
1
require "rexml/text"
-
-
1
module REXML
-
1
class CData < Text
-
1
START = '<![CDATA['
-
1
STOP = ']]>'
-
1
ILLEGAL = /(\]\]>)/
-
-
# Constructor. CData is data between <![CDATA[ ... ]]>
-
#
-
# _Examples_
-
# CData.new( source )
-
# CData.new( "Here is some CDATA" )
-
# CData.new( "Some unprocessed data", respect_whitespace_TF, parent_element )
-
1
def initialize( first, whitespace=true, parent=nil )
-
super( first, whitespace, parent, false, true, ILLEGAL )
-
end
-
-
# Make a copy of this object
-
#
-
# _Examples_
-
# c = CData.new( "Some text" )
-
# d = c.clone
-
# d.to_s # -> "Some text"
-
1
def clone
-
CData.new self
-
end
-
-
# Returns the content of this CData object
-
#
-
# _Examples_
-
# c = CData.new( "Some text" )
-
# c.to_s # -> "Some text"
-
1
def to_s
-
@string
-
end
-
-
1
def value
-
@string
-
end
-
-
# == DEPRECATED
-
# See the rexml/formatters package
-
#
-
# Generates XML output of this object
-
#
-
# output::
-
# Where to write the string. Defaults to $stdout
-
# indent::
-
# The amount to indent this node by
-
# transitive::
-
# Ignored
-
# ie_hack::
-
# Ignored
-
#
-
# _Examples_
-
# c = CData.new( " Some text " )
-
# c.write( $stdout ) #-> <![CDATA[ Some text ]]>
-
1
def write( output=$stdout, indent=-1, transitive=false, ie_hack=false )
-
Kernel.warn( "#{self.class.name}.write is deprecated" )
-
indent( output, indent )
-
output << START
-
output << @string
-
output << STOP
-
end
-
end
-
end
-
1
require "rexml/node"
-
-
1
module REXML
-
##
-
# A Child object is something contained by a parent, and this class
-
# contains methods to support that. Most user code will not use this
-
# class directly.
-
1
class Child
-
1
include Node
-
1
attr_reader :parent # The Parent of this object
-
-
# Constructor. Any inheritors of this class should call super to make
-
# sure this method is called.
-
# parent::
-
# if supplied, the parent of this child will be set to the
-
# supplied value, and self will be added to the parent
-
1
def initialize( parent = nil )
-
225
@parent = nil
-
# Declare @parent, but don't define it. The next line sets the
-
# parent.
-
225
parent.add( self ) if parent
-
end
-
-
# Replaces this object with another object. Basically, calls
-
# Parent.replace_child
-
#
-
# Returns:: self
-
1
def replace_with( child )
-
@parent.replace_child( self, child )
-
self
-
end
-
-
# Removes this child from the parent.
-
#
-
# Returns:: self
-
1
def remove
-
unless @parent.nil?
-
@parent.delete self
-
end
-
self
-
end
-
-
# Sets the parent of this child to the supplied argument.
-
#
-
# other::
-
# Must be a Parent object. If this object is the same object as the
-
# existing parent of this child, no action is taken. Otherwise, this
-
# child is removed from the current parent (if one exists), and is added
-
# to the new parent.
-
# Returns:: The parent added
-
1
def parent=( other )
-
584
return @parent if @parent == other
-
584
@parent.delete self if defined? @parent and @parent
-
584
@parent = other
-
end
-
-
1
alias :next_sibling :next_sibling_node
-
1
alias :previous_sibling :previous_sibling_node
-
-
# Sets the next sibling of this child. This can be used to insert a child
-
# after some other child.
-
# a = Element.new("a")
-
# b = a.add_element("b")
-
# c = Element.new("c")
-
# b.next_sibling = c
-
# # => <a><b/><c/></a>
-
1
def next_sibling=( other )
-
parent.insert_after self, other
-
end
-
-
# Sets the previous sibling of this child. This can be used to insert a
-
# child before some other child.
-
# a = Element.new("a")
-
# b = a.add_element("b")
-
# c = Element.new("c")
-
# b.previous_sibling = c
-
# # => <a><b/><c/></a>
-
1
def previous_sibling=(other)
-
parent.insert_before self, other
-
end
-
-
# Returns:: the document this child belongs to, or nil if this child
-
# belongs to no document
-
1
def document
-
return parent.document unless parent.nil?
-
nil
-
end
-
-
# This doesn't yet handle encodings
-
1
def bytes
-
document.encoding
-
-
to_s
-
end
-
end
-
end
-
1
require "rexml/child"
-
-
1
module REXML
-
##
-
# Represents an XML comment; that is, text between \<!-- ... -->
-
1
class Comment < Child
-
1
include Comparable
-
1
START = "<!--"
-
1
STOP = "-->"
-
-
# The content text
-
-
1
attr_accessor :string
-
-
##
-
# Constructor. The first argument can be one of three types:
-
# @param first If String, the contents of this comment are set to the
-
# argument. If Comment, the argument is duplicated. If
-
# Source, the argument is scanned for a comment.
-
# @param second If the first argument is a Source, this argument
-
# should be nil, not supplied, or a Parent to be set as the parent
-
# of this object
-
1
def initialize( first, second = nil )
-
#puts "IN COMMENT CONSTRUCTOR; SECOND IS #{second.type}"
-
super(second)
-
if first.kind_of? String
-
@string = first
-
elsif first.kind_of? Comment
-
@string = first.string
-
end
-
end
-
-
1
def clone
-
Comment.new self
-
end
-
-
# == DEPRECATED
-
# See REXML::Formatters
-
#
-
# output::
-
# Where to write the string
-
# indent::
-
# An integer. If -1, no indenting will be used; otherwise, the
-
# indentation will be this number of spaces, and children will be
-
# indented an additional amount.
-
# transitive::
-
# Ignored by this class. The contents of comments are never modified.
-
# ie_hack::
-
# Needed for conformity to the child API, but not used by this class.
-
1
def write( output, indent=-1, transitive=false, ie_hack=false )
-
Kernel.warn("Comment.write is deprecated. See REXML::Formatters")
-
indent( output, indent )
-
output << START
-
output << @string
-
output << STOP
-
end
-
-
1
alias :to_s :string
-
-
##
-
# Compares this Comment to another; the contents of the comment are used
-
# in the comparison.
-
1
def <=>(other)
-
other.to_s <=> @string
-
end
-
-
##
-
# Compares this Comment to another; the contents of the comment are used
-
# in the comparison.
-
1
def ==( other )
-
other.kind_of? Comment and
-
(other <=> self) == 0
-
end
-
-
1
def node_type
-
:comment
-
end
-
end
-
end
-
#vim:ts=2 sw=2 noexpandtab:
-
1
require "rexml/parent"
-
1
require "rexml/parseexception"
-
1
require "rexml/namespace"
-
1
require 'rexml/entity'
-
1
require 'rexml/attlistdecl'
-
1
require 'rexml/xmltokens'
-
-
1
module REXML
-
# Represents an XML DOCTYPE declaration; that is, the contents of <!DOCTYPE
-
# ... >. DOCTYPES can be used to declare the DTD of a document, as well as
-
# being used to declare entities used in the document.
-
1
class DocType < Parent
-
1
include XMLTokens
-
1
START = "<!DOCTYPE"
-
1
STOP = ">"
-
1
SYSTEM = "SYSTEM"
-
1
PUBLIC = "PUBLIC"
-
1
DEFAULT_ENTITIES = {
-
'gt'=>EntityConst::GT,
-
'lt'=>EntityConst::LT,
-
'quot'=>EntityConst::QUOT,
-
"apos"=>EntityConst::APOS
-
}
-
-
# name is the name of the doctype
-
# external_id is the referenced DTD, if given
-
1
attr_reader :name, :external_id, :entities, :namespaces
-
-
# Constructor
-
#
-
# dt = DocType.new( 'foo', '-//I/Hate/External/IDs' )
-
# # <!DOCTYPE foo '-//I/Hate/External/IDs'>
-
# dt = DocType.new( doctype_to_clone )
-
# # Incomplete. Shallow clone of doctype
-
#
-
# +Note+ that the constructor:
-
#
-
# Doctype.new( Source.new( "<!DOCTYPE foo 'bar'>" ) )
-
#
-
# is _deprecated_. Do not use it. It will probably disappear.
-
1
def initialize( first, parent=nil )
-
@entities = DEFAULT_ENTITIES
-
@long_name = @uri = nil
-
if first.kind_of? String
-
super()
-
@name = first
-
@external_id = parent
-
elsif first.kind_of? DocType
-
super( parent )
-
@name = first.name
-
@external_id = first.external_id
-
elsif first.kind_of? Array
-
super( parent )
-
@name = first[0]
-
@external_id = first[1]
-
@long_name = first[2]
-
@uri = first[3]
-
elsif first.kind_of? Source
-
super( parent )
-
parser = Parsers::BaseParser.new( first )
-
event = parser.pull
-
if event[0] == :start_doctype
-
@name, @external_id, @long_name, @uri, = event[1..-1]
-
end
-
else
-
super()
-
end
-
end
-
-
1
def node_type
-
:doctype
-
end
-
-
1
def attributes_of element
-
rv = []
-
each do |child|
-
child.each do |key,val|
-
rv << Attribute.new(key,val)
-
end if child.kind_of? AttlistDecl and child.element_name == element
-
end
-
rv
-
end
-
-
1
def attribute_of element, attribute
-
att_decl = find do |child|
-
child.kind_of? AttlistDecl and
-
child.element_name == element and
-
child.include? attribute
-
end
-
return nil unless att_decl
-
att_decl[attribute]
-
end
-
-
1
def clone
-
DocType.new self
-
end
-
-
# output::
-
# Where to write the string
-
# indent::
-
# An integer. If -1, no indentation will be used; otherwise, the
-
# indentation will be this number of spaces, and children will be
-
# indented an additional amount.
-
# transitive::
-
# Ignored
-
# ie_hack::
-
# Ignored
-
1
def write( output, indent=0, transitive=false, ie_hack=false )
-
f = REXML::Formatters::Default.new
-
indent( output, indent )
-
output << START
-
output << ' '
-
output << @name
-
output << " #@external_id" if @external_id
-
output << " #{@long_name.inspect}" if @long_name
-
output << " #{@uri.inspect}" if @uri
-
unless @children.empty?
-
output << ' ['
-
@children.each { |child|
-
output << "\n"
-
f.write( child, output )
-
}
-
output << "\n]"
-
end
-
output << STOP
-
end
-
-
1
def context
-
@parent.context
-
end
-
-
1
def entity( name )
-
@entities[name].unnormalized if @entities[name]
-
end
-
-
1
def add child
-
super(child)
-
@entities = DEFAULT_ENTITIES.clone if @entities == DEFAULT_ENTITIES
-
@entities[ child.name ] = child if child.kind_of? Entity
-
end
-
-
# This method retrieves the public identifier identifying the document's
-
# DTD.
-
#
-
# Method contributed by Henrik Martensson
-
1
def public
-
case @external_id
-
when "SYSTEM"
-
nil
-
when "PUBLIC"
-
strip_quotes(@long_name)
-
end
-
end
-
-
# This method retrieves the system identifier identifying the document's DTD
-
#
-
# Method contributed by Henrik Martensson
-
1
def system
-
case @external_id
-
when "SYSTEM"
-
strip_quotes(@long_name)
-
when "PUBLIC"
-
@uri.kind_of?(String) ? strip_quotes(@uri) : nil
-
end
-
end
-
-
# This method returns a list of notations that have been declared in the
-
# _internal_ DTD subset. Notations in the external DTD subset are not
-
# listed.
-
#
-
# Method contributed by Henrik Martensson
-
1
def notations
-
children().select {|node| node.kind_of?(REXML::NotationDecl)}
-
end
-
-
# Retrieves a named notation. Only notations declared in the internal
-
# DTD subset can be retrieved.
-
#
-
# Method contributed by Henrik Martensson
-
1
def notation(name)
-
notations.find { |notation_decl|
-
notation_decl.name == name
-
}
-
end
-
-
1
private
-
-
# Method contributed by Henrik Martensson
-
1
def strip_quotes(quoted_string)
-
quoted_string =~ /^[\'\"].*[\'\"]$/ ?
-
quoted_string[1, quoted_string.length-2] :
-
quoted_string
-
end
-
end
-
-
# We don't really handle any of these since we're not a validating
-
# parser, so we can be pretty dumb about them. All we need to be able
-
# to do is spew them back out on a write()
-
-
# This is an abstract class. You never use this directly; it serves as a
-
# parent class for the specific declarations.
-
1
class Declaration < Child
-
1
def initialize src
-
super()
-
@string = src
-
end
-
-
1
def to_s
-
@string+'>'
-
end
-
-
# == DEPRECATED
-
# See REXML::Formatters
-
#
-
1
def write( output, indent )
-
output << to_s
-
end
-
end
-
-
1
public
-
1
class ElementDecl < Declaration
-
1
def initialize( src )
-
super
-
end
-
end
-
-
1
class ExternalEntity < Child
-
1
def initialize( src )
-
super()
-
@entity = src
-
end
-
1
def to_s
-
@entity
-
end
-
1
def write( output, indent )
-
output << @entity
-
end
-
end
-
-
1
class NotationDecl < Child
-
1
attr_accessor :public, :system
-
1
def initialize name, middle, pub, sys
-
super(nil)
-
@name = name
-
@middle = middle
-
@public = pub
-
@system = sys
-
end
-
-
1
def to_s
-
notation = "<!NOTATION #{@name} #{@middle}"
-
notation << " #{@public.inspect}" if @public
-
notation << " #{@system.inspect}" if @system
-
notation << ">"
-
notation
-
end
-
-
1
def write( output, indent=-1 )
-
output << to_s
-
end
-
-
# This method retrieves the name of the notation.
-
#
-
# Method contributed by Henrik Martensson
-
1
def name
-
@name
-
end
-
end
-
end
-
1
require "rexml/element"
-
1
require "rexml/xmldecl"
-
1
require "rexml/source"
-
1
require "rexml/comment"
-
1
require "rexml/doctype"
-
1
require "rexml/instruction"
-
1
require "rexml/rexml"
-
1
require "rexml/parseexception"
-
1
require "rexml/output"
-
1
require "rexml/parsers/baseparser"
-
1
require "rexml/parsers/streamparser"
-
1
require "rexml/parsers/treeparser"
-
-
1
module REXML
-
# Represents a full XML document, including PIs, a doctype, etc. A
-
# Document has a single child that can be accessed by root().
-
# Note that if you want to have an XML declaration written for a document
-
# you create, you must add one; REXML documents do not write a default
-
# declaration for you. See |DECLARATION| and |write|.
-
1
class Document < Element
-
# A convenient default XML declaration. If you want an XML declaration,
-
# the easiest way to add one is mydoc << Document::DECLARATION
-
# +DEPRECATED+
-
# Use: mydoc << XMLDecl.default
-
1
DECLARATION = XMLDecl.default
-
-
# Constructor
-
# @param source if supplied, must be a Document, String, or IO.
-
# Documents have their context and Element attributes cloned.
-
# Strings are expected to be valid XML documents. IOs are expected
-
# to be sources of valid XML documents.
-
# @param context if supplied, contains the context of the document;
-
# this should be a Hash.
-
1
def initialize( source = nil, context = {} )
-
9
@entity_expansion_count = 0
-
9
super()
-
9
@context = context
-
9
return if source.nil?
-
9
if source.kind_of? Document
-
@context = source.context
-
super source
-
else
-
9
build( source )
-
end
-
end
-
-
1
def node_type
-
57
:document
-
end
-
-
# Should be obvious
-
1
def clone
-
Document.new self
-
end
-
-
# According to the XML spec, a root node has no expanded name
-
1
def expanded_name
-
''
-
#d = doc_type
-
#d ? d.name : "UNDEFINED"
-
end
-
-
1
alias :name :expanded_name
-
-
# We override this, because XMLDecls and DocTypes must go at the start
-
# of the document
-
1
def add( child )
-
34
if child.kind_of? XMLDecl
-
9
if @children[0].kind_of? XMLDecl
-
@children[0] = child
-
else
-
9
@children.unshift child
-
end
-
9
child.parent = self
-
25
elsif child.kind_of? DocType
-
# Find first Element or DocType node and insert the decl right
-
# before it. If there is no such node, just insert the child at the
-
# end. If there is a child and it is an DocType, then replace it.
-
insert_before_index = @children.find_index { |x|
-
x.kind_of?(Element) || x.kind_of?(DocType)
-
}
-
if insert_before_index # Not null = not end of list
-
if @children[ insert_before_index ].kind_of? DocType
-
@children[ insert_before_index ] = child
-
else
-
@children[ insert_before_index-1, 0 ] = child
-
end
-
else # Insert at end of list
-
@children << child
-
end
-
child.parent = self
-
else
-
25
rv = super
-
25
raise "attempted adding second root element to document" if @elements.size > 1
-
25
rv
-
end
-
end
-
1
alias :<< :add
-
-
1
def add_element(arg=nil, arg2=nil)
-
9
rv = super
-
9
raise "attempted adding second root element to document" if @elements.size > 1
-
9
rv
-
end
-
-
# @return the root Element of the document, or nil if this document
-
# has no children.
-
1
def root
-
375
elements[1]
-
#self
-
#@children.find { |item| item.kind_of? Element }
-
end
-
-
# @return the DocType child of the document, if one exists,
-
# and nil otherwise.
-
1
def doctype
-
6641
@children.find { |item| item.kind_of? DocType }
-
end
-
-
# @return the XMLDecl of this document; if no XMLDecl has been
-
# set, the default declaration is returned.
-
1
def xml_decl
-
rv = @children[0]
-
return rv if rv.kind_of? XMLDecl
-
rv = @children.unshift(XMLDecl.default)[0]
-
end
-
-
# @return the XMLDecl version of this document as a String.
-
# If no XMLDecl has been set, returns the default version.
-
1
def version
-
xml_decl().version
-
end
-
-
# @return the XMLDecl encoding of this document as an
-
# Encoding object.
-
# If no XMLDecl has been set, returns the default encoding.
-
1
def encoding
-
xml_decl().encoding
-
end
-
-
# @return the XMLDecl standalone value of this document as a String.
-
# If no XMLDecl has been set, returns the default setting.
-
1
def stand_alone?
-
xml_decl().stand_alone?
-
end
-
-
# Write the XML tree out, optionally with indent. This writes out the
-
# entire XML document, including XML declarations, doctype declarations,
-
# and processing instructions (if any are given).
-
#
-
# A controversial point is whether Document should always write the XML
-
# declaration (<?xml version='1.0'?>) whether or not one is given by the
-
# user (or source document). REXML does not write one if one was not
-
# specified, because it adds unnecessary bandwidth to applications such
-
# as XML-RPC.
-
#
-
# See also the classes in the rexml/formatters package for the proper way
-
# to change the default formatting of XML output
-
#
-
# _Examples_
-
# Document.new("<a><b/></a>").serialize
-
#
-
# output_string = ""
-
# tr = Transitive.new( output_string )
-
# Document.new("<a><b/></a>").serialize( tr )
-
#
-
# output::
-
# output an object which supports '<< string'; this is where the
-
# document will be written.
-
# indent::
-
# An integer. If -1, no indenting will be used; otherwise, the
-
# indentation will be twice this number of spaces, and children will be
-
# indented an additional amount. For a value of 3, every item will be
-
# indented 3 more levels, or 6 more spaces (2 * 3). Defaults to -1
-
# transitive::
-
# If transitive is true and indent is >= 0, then the output will be
-
# pretty-printed in such a way that the added whitespace does not affect
-
# the absolute *value* of the document -- that is, it leaves the value
-
# and number of Text nodes in the document unchanged.
-
# ie_hack::
-
# Internet Explorer is the worst piece of crap to have ever been
-
# written, with the possible exception of Windows itself. Since IE is
-
# unable to parse proper XML, we have to provide a hack to generate XML
-
# that IE's limited abilities can handle. This hack inserts a space
-
# before the /> on empty tags. Defaults to false
-
1
def write( output=$stdout, indent=-1, transitive=false, ie_hack=false )
-
if xml_decl.encoding != 'UTF-8' && !output.kind_of?(Output)
-
output = Output.new( output, xml_decl.encoding )
-
end
-
formatter = if indent > -1
-
if transitive
-
require "rexml/formatters/transitive"
-
REXML::Formatters::Transitive.new( indent, ie_hack )
-
else
-
REXML::Formatters::Pretty.new( indent, ie_hack )
-
end
-
else
-
REXML::Formatters::Default.new( ie_hack )
-
end
-
formatter.write( self, output )
-
end
-
-
-
1
def Document::parse_stream( source, listener )
-
Parsers::StreamParser.new( source, listener ).parse
-
end
-
-
1
@@entity_expansion_limit = 10_000
-
-
# Set the entity expansion limit. By default the limit is set to 10000.
-
1
def Document::entity_expansion_limit=( val )
-
@@entity_expansion_limit = val
-
end
-
-
# Get the entity expansion limit. By default the limit is set to 10000.
-
1
def Document::entity_expansion_limit
-
return @@entity_expansion_limit
-
end
-
-
1
attr_reader :entity_expansion_count
-
-
1
def record_entity_expansion
-
@entity_expansion_count += 1
-
if @entity_expansion_count > @@entity_expansion_limit
-
raise "number of entity expansions exceeded, processing aborted."
-
end
-
end
-
-
1
private
-
1
def build( source )
-
9
Parsers::TreeParser.new( source, self ).parse
-
end
-
end
-
end
-
1
require "rexml/parent"
-
1
require "rexml/namespace"
-
1
require "rexml/attribute"
-
1
require "rexml/cdata"
-
1
require "rexml/xpath"
-
1
require "rexml/parseexception"
-
-
1
module REXML
-
# An implementation note about namespaces:
-
# As we parse, when we find namespaces we put them in a hash and assign
-
# them a unique ID. We then convert the namespace prefix for the node
-
# to the unique ID. This makes namespace lookup much faster for the
-
# cost of extra memory use. We save the namespace prefix for the
-
# context node and convert it back when we write it.
-
1
@@namespaces = {}
-
-
# Represents a tagged XML element. Elements are characterized by
-
# having children, attributes, and names, and can themselves be
-
# children.
-
1
class Element < Parent
-
1
include Namespace
-
-
1
UNDEFINED = "UNDEFINED"; # The default name
-
-
# Mechanisms for accessing attributes and child elements of this
-
# element.
-
1
attr_reader :attributes, :elements
-
# The context holds information about the processing environment, such as
-
# whitespace handling.
-
1
attr_accessor :context
-
-
# Constructor
-
# arg::
-
# if not supplied, will be set to the default value.
-
# If a String, the name of this object will be set to the argument.
-
# If an Element, the object will be shallowly cloned; name,
-
# attributes, and namespaces will be copied. Children will +not+ be
-
# copied.
-
# parent::
-
# if supplied, must be a Parent, and will be used as
-
# the parent of this object.
-
# context::
-
# If supplied, must be a hash containing context items. Context items
-
# include:
-
# * <tt>:respect_whitespace</tt> the value of this is :+all+ or an array of
-
# strings being the names of the elements to respect
-
# whitespace for. Defaults to :+all+.
-
# * <tt>:compress_whitespace</tt> the value can be :+all+ or an array of
-
# strings being the names of the elements to ignore whitespace on.
-
# Overrides :+respect_whitespace+.
-
# * <tt>:ignore_whitespace_nodes</tt> the value can be :+all+ or an array
-
# of strings being the names of the elements in which to ignore
-
# whitespace-only nodes. If this is set, Text nodes which contain only
-
# whitespace will not be added to the document tree.
-
# * <tt>:raw</tt> can be :+all+, or an array of strings being the names of
-
# the elements to process in raw mode. In raw mode, special
-
# characters in text is not converted to or from entities.
-
1
def initialize( arg = UNDEFINED, parent=nil, context=nil )
-
210
super(parent)
-
-
210
@elements = Elements.new(self)
-
210
@attributes = Attributes.new(self)
-
210
@context = context
-
-
210
if arg.kind_of? String
-
210
self.name = arg
-
elsif arg.kind_of? Element
-
self.name = arg.expanded_name
-
arg.attributes.each_attribute{ |attribute|
-
@attributes << Attribute.new( attribute )
-
}
-
@context = arg.context
-
end
-
end
-
-
1
def inspect
-
rv = "<#@expanded_name"
-
-
@attributes.each_attribute do |attr|
-
rv << " "
-
attr.write( rv, 0 )
-
end
-
-
if children.size > 0
-
rv << "> ... </>"
-
else
-
rv << "/>"
-
end
-
end
-
-
-
# Creates a shallow copy of self.
-
# d = Document.new "<a><b/><b/><c><d/></c></a>"
-
# new_a = d.root.clone
-
# puts new_a # => "<a/>"
-
1
def clone
-
self.class.new self
-
end
-
-
# Evaluates to the root node of the document that this element
-
# belongs to. If this element doesn't belong to a document, but does
-
# belong to another Element, the parent's root will be returned, until the
-
# earliest ancestor is found.
-
#
-
# Note that this is not the same as the document element.
-
# In the following example, <a> is the document element, and the root
-
# node is the parent node of the document element. You may ask yourself
-
# why the root node is useful: consider the doctype and XML declaration,
-
# and any processing instructions before the document element... they
-
# are children of the root node, or siblings of the document element.
-
# The only time this isn't true is when an Element is created that is
-
# not part of any Document. In this case, the ancestor that has no
-
# parent acts as the root node.
-
# d = Document.new '<a><b><c/></b></a>'
-
# a = d[1] ; c = a[1][1]
-
# d.root_node == d # TRUE
-
# a.root_node # namely, d
-
# c.root_node # again, d
-
1
def root_node
-
19
parent.nil? ? self : parent.root_node
-
end
-
-
1
def root
-
3569
return elements[1] if self.kind_of? Document
-
3569
return self if parent.kind_of? Document or parent.nil?
-
2070
return parent.root
-
end
-
-
# Evaluates to the document to which this element belongs, or nil if this
-
# element doesn't belong to a document.
-
1
def document
-
1857
rt = root
-
1857
rt.parent if rt
-
end
-
-
# Evaluates to +true+ if whitespace is respected for this element. This
-
# is the case if:
-
# 1. Neither :+respect_whitespace+ nor :+compress_whitespace+ has any value
-
# 2. The context has :+respect_whitespace+ set to :+all+ or
-
# an array containing the name of this element, and
-
# :+compress_whitespace+ isn't set to :+all+ or an array containing the
-
# name of this element.
-
# The evaluation is tested against +expanded_name+, and so is namespace
-
# sensitive.
-
1
def whitespace
-
374
@whitespace = nil
-
374
if @context
-
374
if @context[:respect_whitespace]
-
@whitespace = (@context[:respect_whitespace] == :all or
-
@context[:respect_whitespace].include? expanded_name)
-
end
-
@whitespace = false if (@context[:compress_whitespace] and
-
(@context[:compress_whitespace] == :all or
-
374
@context[:compress_whitespace].include? expanded_name)
-
)
-
end
-
374
@whitespace = true unless @whitespace == false
-
374
@whitespace
-
end
-
-
1
def ignore_whitespace_nodes
-
374
@ignore_whitespace_nodes = false
-
374
if @context
-
374
if @context[:ignore_whitespace_nodes]
-
@ignore_whitespace_nodes =
-
(@context[:ignore_whitespace_nodes] == :all or
-
@context[:ignore_whitespace_nodes].include? expanded_name)
-
end
-
end
-
end
-
-
# Evaluates to +true+ if raw mode is set for this element. This
-
# is the case if the context has :+raw+ set to :+all+ or
-
# an array containing the name of this element.
-
#
-
# The evaluation is tested against +expanded_name+, and so is namespace
-
# sensitive.
-
1
def raw
-
@raw = (@context and @context[:raw] and
-
(@context[:raw] == :all or
-
@context[:raw].include? expanded_name))
-
@raw
-
end
-
-
#once :whitespace, :raw, :ignore_whitespace_nodes
-
-
#################################################
-
# Namespaces #
-
#################################################
-
-
# Evaluates to an +Array+ containing the prefixes (names) of all defined
-
# namespaces at this context node.
-
# doc = Document.new("<a xmlns:x='1' xmlns:y='2'><b/><c xmlns:z='3'/></a>")
-
# doc.elements['//b'].prefixes # -> ['x', 'y']
-
1
def prefixes
-
prefixes = []
-
prefixes = parent.prefixes if parent
-
prefixes |= attributes.prefixes
-
return prefixes
-
end
-
-
1
def namespaces
-
namespaces = {}
-
namespaces = parent.namespaces if parent
-
namespaces = namespaces.merge( attributes.namespaces )
-
return namespaces
-
end
-
-
# Evalutas to the URI for a prefix, or the empty string if no such
-
# namespace is declared for this element. Evaluates recursively for
-
# ancestors. Returns the default namespace, if there is one.
-
# prefix::
-
# the prefix to search for. If not supplied, returns the default
-
# namespace if one exists
-
# Returns::
-
# the namespace URI as a String, or nil if no such namespace
-
# exists. If the namespace is undefined, returns an empty string
-
# doc = Document.new("<a xmlns='1' xmlns:y='2'><b/><c xmlns:z='3'/></a>")
-
# b = doc.elements['//b']
-
# b.namespace # -> '1'
-
# b.namespace("y") # -> '2'
-
1
def namespace(prefix=nil)
-
1007
if prefix.nil?
-
19
prefix = prefix()
-
end
-
1007
if prefix == ''
-
342
prefix = "xmlns"
-
else
-
665
prefix = "xmlns:#{prefix}" unless prefix[0,5] == 'xmlns'
-
end
-
1007
ns = attributes[ prefix ]
-
1007
ns = parent.namespace(prefix) if ns.nil? and parent
-
1007
ns = '' if ns.nil? and prefix == 'xmlns'
-
1007
return ns
-
end
-
-
# Adds a namespace to this element.
-
# prefix::
-
# the prefix string, or the namespace URI if +uri+ is not
-
# supplied
-
# uri::
-
# the namespace URI. May be nil, in which +prefix+ is used as
-
# the URI
-
# Evaluates to: this Element
-
# a = Element.new("a")
-
# a.add_namespace("xmlns:foo", "bar" )
-
# a.add_namespace("foo", "bar") # shorthand for previous line
-
# a.add_namespace("twiddle")
-
# puts a #-> <a xmlns:foo='bar' xmlns='twiddle'/>
-
1
def add_namespace( prefix, uri=nil )
-
unless uri
-
@attributes["xmlns"] = prefix
-
else
-
prefix = "xmlns:#{prefix}" unless prefix =~ /^xmlns:/
-
@attributes[ prefix ] = uri
-
end
-
self
-
end
-
-
# Removes a namespace from this node. This only works if the namespace is
-
# actually declared in this node. If no argument is passed, deletes the
-
# default namespace.
-
#
-
# Evaluates to: this element
-
# doc = Document.new "<a xmlns:foo='bar' xmlns='twiddle'/>"
-
# doc.root.delete_namespace
-
# puts doc # -> <a xmlns:foo='bar'/>
-
# doc.root.delete_namespace 'foo'
-
# puts doc # -> <a/>
-
1
def delete_namespace namespace="xmlns"
-
namespace = "xmlns:#{namespace}" unless namespace == 'xmlns'
-
attribute = attributes.get_attribute(namespace)
-
attribute.remove unless attribute.nil?
-
self
-
end
-
-
#################################################
-
# Elements #
-
#################################################
-
-
# Adds a child to this element, optionally setting attributes in
-
# the element.
-
# element::
-
# optional. If Element, the element is added.
-
# Otherwise, a new Element is constructed with the argument (see
-
# Element.initialize).
-
# attrs::
-
# If supplied, must be a Hash containing String name,value
-
# pairs, which will be used to set the attributes of the new Element.
-
# Returns:: the Element that was added
-
# el = doc.add_element 'my-tag'
-
# el = doc.add_element 'my-tag', {'attr1'=>'val1', 'attr2'=>'val2'}
-
# el = Element.new 'my-tag'
-
# doc.add_element el
-
1
def add_element element, attrs=nil
-
201
raise "First argument must be either an element name, or an Element object" if element.nil?
-
201
el = @elements.add(element)
-
attrs.each do |key, value|
-
el.attributes[key]=value
-
201
end if attrs.kind_of? Hash
-
201
el
-
end
-
-
# Deletes a child element.
-
# element::
-
# Must be an +Element+, +String+, or +Integer+. If Element,
-
# the element is removed. If String, the element is found (via XPath)
-
# and removed. <em>This means that any parent can remove any
-
# descendant.<em> If Integer, the Element indexed by that number will be
-
# removed.
-
# Returns:: the element that was removed.
-
# doc.delete_element "/a/b/c[@id='4']"
-
# doc.delete_element doc.elements["//k"]
-
# doc.delete_element 1
-
1
def delete_element element
-
@elements.delete element
-
end
-
-
# Evaluates to +true+ if this element has at least one child Element
-
# doc = Document.new "<a><b/><c>Text</c></a>"
-
# doc.root.has_elements # -> true
-
# doc.elements["/a/b"].has_elements # -> false
-
# doc.elements["/a/c"].has_elements # -> false
-
1
def has_elements?
-
184
!@elements.empty?
-
end
-
-
# Iterates through the child elements, yielding for each Element that
-
# has a particular attribute set.
-
# key::
-
# the name of the attribute to search for
-
# value::
-
# the value of the attribute
-
# max::
-
# (optional) causes this method to return after yielding
-
# for this number of matching children
-
# name::
-
# (optional) if supplied, this is an XPath that filters
-
# the children to check.
-
#
-
# doc = Document.new "<a><b @id='1'/><c @id='2'/><d @id='1'/><e/></a>"
-
# # Yields b, c, d
-
# doc.root.each_element_with_attribute( 'id' ) {|e| p e}
-
# # Yields b, d
-
# doc.root.each_element_with_attribute( 'id', '1' ) {|e| p e}
-
# # Yields b
-
# doc.root.each_element_with_attribute( 'id', '1', 1 ) {|e| p e}
-
# # Yields d
-
# doc.root.each_element_with_attribute( 'id', '1', 0, 'd' ) {|e| p e}
-
1
def each_element_with_attribute( key, value=nil, max=0, name=nil, &block ) # :yields: Element
-
each_with_something( proc {|child|
-
if value.nil?
-
child.attributes[key] != nil
-
else
-
child.attributes[key]==value
-
end
-
}, max, name, &block )
-
end
-
-
# Iterates through the children, yielding for each Element that
-
# has a particular text set.
-
# text::
-
# the text to search for. If nil, or not supplied, will iterate
-
# over all +Element+ children that contain at least one +Text+ node.
-
# max::
-
# (optional) causes this method to return after yielding
-
# for this number of matching children
-
# name::
-
# (optional) if supplied, this is an XPath that filters
-
# the children to check.
-
#
-
# doc = Document.new '<a><b>b</b><c>b</c><d>d</d><e/></a>'
-
# # Yields b, c, d
-
# doc.each_element_with_text {|e|p e}
-
# # Yields b, c
-
# doc.each_element_with_text('b'){|e|p e}
-
# # Yields b
-
# doc.each_element_with_text('b', 1){|e|p e}
-
# # Yields d
-
# doc.each_element_with_text(nil, 0, 'd'){|e|p e}
-
1
def each_element_with_text( text=nil, max=0, name=nil, &block ) # :yields: Element
-
each_with_something( proc {|child|
-
if text.nil?
-
child.has_text?
-
else
-
child.text == text
-
end
-
}, max, name, &block )
-
end
-
-
# Synonym for Element.elements.each
-
1
def each_element( xpath=nil, &block ) # :yields: Element
-
25
@elements.each( xpath, &block )
-
end
-
-
# Synonym for Element.to_a
-
# This is a little slower than calling elements.each directly.
-
# xpath:: any XPath by which to search for elements in the tree
-
# Returns:: an array of Elements that match the supplied path
-
1
def get_elements( xpath )
-
@elements.to_a( xpath )
-
end
-
-
# Returns the next sibling that is an element, or nil if there is
-
# no Element sibling after this one
-
# doc = Document.new '<a><b/>text<c/></a>'
-
# doc.root.elements['b'].next_element #-> <c/>
-
# doc.root.elements['c'].next_element #-> nil
-
1
def next_element
-
element = next_sibling
-
element = element.next_sibling until element.nil? or element.kind_of? Element
-
return element
-
end
-
-
# Returns the previous sibling that is an element, or nil if there is
-
# no Element sibling prior to this one
-
# doc = Document.new '<a><b/>text<c/></a>'
-
# doc.root.elements['c'].previous_element #-> <b/>
-
# doc.root.elements['b'].previous_element #-> nil
-
1
def previous_element
-
element = previous_sibling
-
element = element.previous_sibling until element.nil? or element.kind_of? Element
-
return element
-
end
-
-
-
#################################################
-
# Text #
-
#################################################
-
-
# Evaluates to +true+ if this element has at least one Text child
-
1
def has_text?
-
159
not text().nil?
-
end
-
-
# A convenience method which returns the String value of the _first_
-
# child text element, if one exists, and +nil+ otherwise.
-
#
-
# <em>Note that an element may have multiple Text elements, perhaps
-
# separated by other children</em>. Be aware that this method only returns
-
# the first Text node.
-
#
-
# This method returns the +value+ of the first text child node, which
-
# ignores the +raw+ setting, so always returns normalized text. See
-
# the Text::value documentation.
-
#
-
# doc = Document.new "<p>some text <b>this is bold!</b> more text</p>"
-
# # The element 'p' has two text elements, "some text " and " more text".
-
# doc.root.text #-> "some text "
-
1
def text( path = nil )
-
170
rv = get_text(path)
-
170
return rv.value unless rv.nil?
-
nil
-
end
-
-
# Returns the first child Text node, if any, or +nil+ otherwise.
-
# This method returns the actual +Text+ node, rather than the String content.
-
# doc = Document.new "<p>some text <b>this is bold!</b> more text</p>"
-
# # The element 'p' has two text elements, "some text " and " more text".
-
# doc.root.get_text.value #-> "some text "
-
1
def get_text path = nil
-
170
rv = nil
-
170
if path
-
element = @elements[ path ]
-
rv = element.get_text unless element.nil?
-
else
-
325
rv = @children.find { |node| node.kind_of? Text }
-
end
-
170
return rv
-
end
-
-
# Sets the first Text child of this object. See text() for a
-
# discussion about Text children.
-
#
-
# If a Text child already exists, the child is replaced by this
-
# content. This means that Text content can be deleted by calling
-
# this method with a nil argument. In this case, the next Text
-
# child becomes the first Text child. In no case is the order of
-
# any siblings disturbed.
-
# text::
-
# If a String, a new Text child is created and added to
-
# this Element as the first Text child. If Text, the text is set
-
# as the first Child element. If nil, then any existing first Text
-
# child is removed.
-
# Returns:: this Element.
-
# doc = Document.new '<a><b/></a>'
-
# doc.root.text = 'Sean' #-> '<a><b/>Sean</a>'
-
# doc.root.text = 'Elliott' #-> '<a><b/>Elliott</a>'
-
# doc.root.add_element 'c' #-> '<a><b/>Elliott<c/></a>'
-
# doc.root.text = 'Russell' #-> '<a><b/>Russell<c/></a>'
-
# doc.root.text = nil #-> '<a><b/><c/></a>'
-
1
def text=( text )
-
if text.kind_of? String
-
text = Text.new( text, whitespace(), nil, raw() )
-
elsif !text.nil? and !text.kind_of? Text
-
text = Text.new( text.to_s, whitespace(), nil, raw() )
-
end
-
old_text = get_text
-
if text.nil?
-
old_text.remove unless old_text.nil?
-
else
-
if old_text.nil?
-
self << text
-
else
-
old_text.replace_with( text )
-
end
-
end
-
return self
-
end
-
-
# A helper method to add a Text child. Actual Text instances can
-
# be added with regular Parent methods, such as add() and <<()
-
# text::
-
# if a String, a new Text instance is created and added
-
# to the parent. If Text, the object is added directly.
-
# Returns:: this Element
-
# e = Element.new('a') #-> <e/>
-
# e.add_text 'foo' #-> <e>foo</e>
-
# e.add_text Text.new(' bar') #-> <e>foo bar</e>
-
# Note that at the end of this example, the branch has <b>3</b> nodes; the 'e'
-
# element and <b>2</b> Text node children.
-
1
def add_text( text )
-
if text.kind_of? String
-
if @children[-1].kind_of? Text
-
@children[-1] << text
-
return
-
end
-
text = Text.new( text, whitespace(), nil, raw() )
-
end
-
self << text unless text.nil?
-
return self
-
end
-
-
1
def node_type
-
1854
:element
-
end
-
-
1
def xpath
-
path_elements = []
-
cur = self
-
path_elements << __to_xpath_helper( self )
-
while cur.parent
-
cur = cur.parent
-
path_elements << __to_xpath_helper( cur )
-
end
-
return path_elements.reverse.join( "/" )
-
end
-
-
#################################################
-
# Attributes #
-
#################################################
-
-
1
def attribute( name, namespace=nil )
-
prefix = nil
-
if namespaces.respond_to? :key
-
prefix = namespaces.key(namespace) if namespace
-
else
-
prefix = namespaces.index(namespace) if namespace
-
end
-
prefix = nil if prefix == 'xmlns'
-
-
ret_val =
-
attributes.get_attribute( "#{prefix ? prefix + ':' : ''}#{name}" )
-
-
return ret_val unless ret_val.nil?
-
return nil if prefix.nil?
-
-
# now check that prefix'es namespace is not the same as the
-
# default namespace
-
return nil unless ( namespaces[ prefix ] == namespaces[ 'xmlns' ] )
-
-
attributes.get_attribute( name )
-
-
end
-
-
# Evaluates to +true+ if this element has any attributes set, false
-
# otherwise.
-
1
def has_attributes?
-
return !@attributes.empty?
-
end
-
-
# Adds an attribute to this element, overwriting any existing attribute
-
# by the same name.
-
# key::
-
# can be either an Attribute or a String. If an Attribute,
-
# the attribute is added to the list of Element attributes. If String,
-
# the argument is used as the name of the new attribute, and the value
-
# parameter must be supplied.
-
# value::
-
# Required if +key+ is a String, and ignored if the first argument is
-
# an Attribute. This is a String, and is used as the value
-
# of the new Attribute. This should be the unnormalized value of the
-
# attribute (without entities).
-
# Returns:: the Attribute added
-
# e = Element.new 'e'
-
# e.add_attribute( 'a', 'b' ) #-> <e a='b'/>
-
# e.add_attribute( 'x:a', 'c' ) #-> <e a='b' x:a='c'/>
-
# e.add_attribute Attribute.new('b', 'd') #-> <e a='b' x:a='c' b='d'/>
-
1
def add_attribute( key, value=nil )
-
if key.kind_of? Attribute
-
@attributes << key
-
else
-
@attributes[key] = value
-
end
-
end
-
-
# Add multiple attributes to this element.
-
# hash:: is either a hash, or array of arrays
-
# el.add_attributes( {"name1"=>"value1", "name2"=>"value2"} )
-
# el.add_attributes( [ ["name1","value1"], ["name2"=>"value2"] ] )
-
1
def add_attributes hash
-
if hash.kind_of? Hash
-
hash.each_pair {|key, value| @attributes[key] = value }
-
elsif hash.kind_of? Array
-
hash.each { |value| @attributes[ value[0] ] = value[1] }
-
end
-
end
-
-
# Removes an attribute
-
# key::
-
# either an Attribute or a String. In either case, the
-
# attribute is found by matching the attribute name to the argument,
-
# and then removed. If no attribute is found, no action is taken.
-
# Returns::
-
# the attribute removed, or nil if this Element did not contain
-
# a matching attribute
-
# e = Element.new('E')
-
# e.add_attribute( 'name', 'Sean' ) #-> <E name='Sean'/>
-
# r = e.add_attribute( 'sur:name', 'Russell' ) #-> <E name='Sean' sur:name='Russell'/>
-
# e.delete_attribute( 'name' ) #-> <E sur:name='Russell'/>
-
# e.delete_attribute( r ) #-> <E/>
-
1
def delete_attribute(key)
-
attr = @attributes.get_attribute(key)
-
attr.remove unless attr.nil?
-
end
-
-
#################################################
-
# Other Utilities #
-
#################################################
-
-
# Get an array of all CData children.
-
# IMMUTABLE
-
1
def cdatas
-
find_all { |child| child.kind_of? CData }.freeze
-
end
-
-
# Get an array of all Comment children.
-
# IMMUTABLE
-
1
def comments
-
find_all { |child| child.kind_of? Comment }.freeze
-
end
-
-
# Get an array of all Instruction children.
-
# IMMUTABLE
-
1
def instructions
-
find_all { |child| child.kind_of? Instruction }.freeze
-
end
-
-
# Get an array of all Text children.
-
# IMMUTABLE
-
1
def texts
-
692
find_all { |child| child.kind_of? Text }.freeze
-
end
-
-
# == DEPRECATED
-
# See REXML::Formatters
-
#
-
# Writes out this element, and recursively, all children.
-
# output::
-
# output an object which supports '<< string'; this is where the
-
# document will be written.
-
# indent::
-
# An integer. If -1, no indenting will be used; otherwise, the
-
# indentation will be this number of spaces, and children will be
-
# indented an additional amount. Defaults to -1
-
# transitive::
-
# If transitive is true and indent is >= 0, then the output will be
-
# pretty-printed in such a way that the added whitespace does not affect
-
# the parse tree of the document
-
# ie_hack::
-
# Internet Explorer is the worst piece of crap to have ever been
-
# written, with the possible exception of Windows itself. Since IE is
-
# unable to parse proper XML, we have to provide a hack to generate XML
-
# that IE's limited abilities can handle. This hack inserts a space
-
# before the /> on empty tags. Defaults to false
-
#
-
# out = ''
-
# doc.write( out ) #-> doc is written to the string 'out'
-
# doc.write( $stdout ) #-> doc written to the console
-
1
def write(output=$stdout, indent=-1, transitive=false, ie_hack=false)
-
Kernel.warn("#{self.class.name}.write is deprecated. See REXML::Formatters")
-
formatter = if indent > -1
-
if transitive
-
require "rexml/formatters/transitive"
-
REXML::Formatters::Transitive.new( indent, ie_hack )
-
else
-
REXML::Formatters::Pretty.new( indent, ie_hack )
-
end
-
else
-
REXML::Formatters::Default.new( ie_hack )
-
end
-
formatter.write( self, output )
-
end
-
-
-
1
private
-
1
def __to_xpath_helper node
-
rv = node.expanded_name.clone
-
if node.parent
-
results = node.parent.find_all {|n|
-
n.kind_of?(REXML::Element) and n.expanded_name == node.expanded_name
-
}
-
if results.length > 1
-
idx = results.index( node )
-
rv << "[#{idx+1}]"
-
end
-
end
-
rv
-
end
-
-
# A private helper method
-
1
def each_with_something( test, max=0, name=nil )
-
num = 0
-
@elements.each( name ){ |child|
-
yield child if test.call(child) and num += 1
-
return if max>0 and num == max
-
}
-
end
-
end
-
-
########################################################################
-
# ELEMENTS #
-
########################################################################
-
-
# A class which provides filtering of children for Elements, and
-
# XPath search support. You are expected to only encounter this class as
-
# the <tt>element.elements</tt> object. Therefore, you are
-
# _not_ expected to instantiate this yourself.
-
1
class Elements
-
1
include Enumerable
-
# Constructor
-
# parent:: the parent Element
-
1
def initialize parent
-
210
@element = parent
-
end
-
-
# Fetches a child element. Filters only Element children, regardless of
-
# the XPath match.
-
# index::
-
# the search parameter. This is either an Integer, which
-
# will be used to find the index'th child Element, or an XPath,
-
# which will be used to search for the Element. <em>Because
-
# of the nature of XPath searches, any element in the connected XML
-
# document can be fetched through any other element.</em> <b>The
-
# Integer index is 1-based, not 0-based.</b> This means that the first
-
# child element is at index 1, not 0, and the +n+th element is at index
-
# +n+, not <tt>n-1</tt>. This is because XPath indexes element children
-
# starting from 1, not 0, and the indexes should be the same.
-
# name::
-
# optional, and only used in the first argument is an
-
# Integer. In that case, the index'th child Element that has the
-
# supplied name will be returned. Note again that the indexes start at 1.
-
# Returns:: the first matching Element, or nil if no child matched
-
# doc = Document.new '<a><b/><c id="1"/><c id="2"/><d/></a>'
-
# doc.root.elements[1] #-> <b/>
-
# doc.root.elements['c'] #-> <c id="1"/>
-
# doc.root.elements[2,'c'] #-> <c id="2"/>
-
1
def []( index, name=nil)
-
394
if index.kind_of? Integer
-
375
raise "index (#{index}) must be >= 1" if index < 1
-
375
name = literalize(name) if name
-
375
num = 0
-
375
@element.find { |child|
-
child.kind_of? Element and
-
766
(name.nil? ? true : child.has_name?( name )) and
-
367
(num += 1) == index
-
}
-
else
-
19
return XPath::first( @element, index )
-
#{ |element|
-
# return element if element.kind_of? Element
-
#}
-
#return nil
-
end
-
end
-
-
# Sets an element, replacing any previous matching element. If no
-
# existing element is found ,the element is added.
-
# index:: Used to find a matching element to replace. See []().
-
# element::
-
# The element to replace the existing element with
-
# the previous element
-
# Returns:: nil if no previous element was found.
-
#
-
# doc = Document.new '<a/>'
-
# doc.root.elements[10] = Element.new('b') #-> <a><b/></a>
-
# doc.root.elements[1] #-> <b/>
-
# doc.root.elements[1] = Element.new('c') #-> <a><c/></a>
-
# doc.root.elements['c'] = Element.new('d') #-> <a><d/></a>
-
1
def []=( index, element )
-
previous = self[index]
-
if previous.nil?
-
@element.add element
-
else
-
previous.replace_with element
-
end
-
return previous
-
end
-
-
# Returns +true+ if there are no +Element+ children, +false+ otherwise
-
1
def empty?
-
379
@element.find{ |child| child.kind_of? Element}.nil?
-
end
-
-
# Returns the index of the supplied child (starting at 1), or -1 if
-
# the element is not a child
-
# element:: an +Element+ child
-
1
def index element
-
rv = 0
-
found = @element.find do |child|
-
child.kind_of? Element and
-
(rv += 1) and
-
child == element
-
end
-
return rv if found == element
-
return -1
-
end
-
-
# Deletes a child Element
-
# element::
-
# Either an Element, which is removed directly; an
-
# xpath, where the first matching child is removed; or an Integer,
-
# where the n'th Element is removed.
-
# Returns:: the removed child
-
# doc = Document.new '<a><b/><c/><c id="1"/></a>'
-
# b = doc.root.elements[1]
-
# doc.root.elements.delete b #-> <a><c/><c id="1"/></a>
-
# doc.elements.delete("a/c[@id='1']") #-> <a><c/></a>
-
# doc.root.elements.delete 1 #-> <a/>
-
1
def delete element
-
if element.kind_of? Element
-
@element.delete element
-
else
-
el = self[element]
-
el.remove if el
-
end
-
end
-
-
# Removes multiple elements. Filters for Element children, regardless of
-
# XPath matching.
-
# xpath:: all elements matching this String path are removed.
-
# Returns:: an Array of Elements that have been removed
-
# doc = Document.new '<a><c/><c/><c/><c/></a>'
-
# deleted = doc.elements.delete_all 'a/c' #-> [<c/>, <c/>, <c/>, <c/>]
-
1
def delete_all( xpath )
-
rv = []
-
XPath::each( @element, xpath) {|element|
-
rv << element if element.kind_of? Element
-
}
-
rv.each do |element|
-
@element.delete element
-
element.remove
-
end
-
return rv
-
end
-
-
# Adds an element
-
# element::
-
# if supplied, is either an Element, String, or
-
# Source (see Element.initialize). If not supplied or nil, a
-
# new, default Element will be constructed
-
# Returns:: the added Element
-
# a = Element.new('a')
-
# a.elements.add(Element.new('b')) #-> <a><b/></a>
-
# a.elements.add('c') #-> <a><b/><c/></a>
-
1
def add element=nil
-
402
if element.nil?
-
Element.new("", self, @element.context)
-
402
elsif not element.kind_of?(Element)
-
201
Element.new(element, self, @element.context)
-
else
-
201
@element << element
-
201
element.context = @element.context
-
201
element
-
end
-
end
-
-
1
alias :<< :add
-
-
# Iterates through all of the child Elements, optionally filtering
-
# them by a given XPath
-
# xpath::
-
# optional. If supplied, this is a String XPath, and is used to
-
# filter the children, so that only matching children are yielded. Note
-
# that XPaths are automatically filtered for Elements, so that
-
# non-Element children will not be yielded
-
# doc = Document.new '<a><b/><c/><d/>sean<b/><c/><d/></a>'
-
# doc.root.each {|e|p e} #-> Yields b, c, d, b, c, d elements
-
# doc.root.each('b') {|e|p e} #-> Yields b, b elements
-
# doc.root.each('child::node()') {|e|p e}
-
# #-> Yields <b/>, <c/>, <d/>, <b/>, <c/>, <d/>
-
# XPath.each(doc.root, 'child::node()', &block)
-
# #-> Yields <b/>, <c/>, <d/>, sean, <b/>, <c/>, <d/>
-
1
def each( xpath=nil, &block)
-
201
XPath::each( @element, xpath ) {|e| yield e if e.kind_of? Element }
-
end
-
-
1
def collect( xpath=nil, &block )
-
collection = []
-
XPath::each( @element, xpath ) {|e|
-
collection << yield(e) if e.kind_of?(Element)
-
}
-
collection
-
end
-
-
1
def inject( xpath=nil, initial=nil, &block )
-
first = true
-
XPath::each( @element, xpath ) {|e|
-
if (e.kind_of? Element)
-
if (first and initial == nil)
-
initial = e
-
first = false
-
else
-
initial = yield( initial, e ) if e.kind_of? Element
-
end
-
end
-
}
-
initial
-
end
-
-
# Returns the number of +Element+ children of the parent object.
-
# doc = Document.new '<a>sean<b/>elliott<b/>russell<b/></a>'
-
# doc.root.size #-> 6, 3 element and 3 text nodes
-
# doc.root.elements.size #-> 3
-
1
def size
-
34
count = 0
-
134
@element.each {|child| count+=1 if child.kind_of? Element }
-
34
count
-
end
-
-
# Returns an Array of Element children. An XPath may be supplied to
-
# filter the children. Only Element children are returned, even if the
-
# supplied XPath matches non-Element children.
-
# doc = Document.new '<a>sean<b/>elliott<c/></a>'
-
# doc.root.elements.to_a #-> [ <b/>, <c/> ]
-
# doc.root.elements.to_a("child::node()") #-> [ <b/>, <c/> ]
-
# XPath.match(doc.root, "child::node()") #-> [ sean, <b/>, elliott, <c/> ]
-
1
def to_a( xpath=nil )
-
rv = XPath.match( @element, xpath )
-
return rv.find_all{|e| e.kind_of? Element} if xpath
-
rv
-
end
-
-
1
private
-
# Private helper class. Removes quotes from quoted strings
-
1
def literalize name
-
name = name[1..-2] if name[0] == ?' or name[0] == ?" #'
-
name
-
end
-
end
-
-
########################################################################
-
# ATTRIBUTES #
-
########################################################################
-
-
# A class that defines the set of Attributes of an Element and provides
-
# operations for accessing elements in that set.
-
1
class Attributes < Hash
-
# Constructor
-
# element:: the Element of which this is an Attribute
-
1
def initialize element
-
210
@element = element
-
end
-
-
# Fetches an attribute value. If you want to get the Attribute itself,
-
# use get_attribute()
-
# name:: an XPath attribute name. Namespaces are relevant here.
-
# Returns::
-
# the String value of the matching attribute, or +nil+ if no
-
# matching attribute was found. This is the unnormalized value
-
# (with entities expanded).
-
#
-
# doc = Document.new "<a foo:att='1' bar:att='2' att='<'/>"
-
# doc.root.attributes['att'] #-> '<'
-
# doc.root.attributes['bar:att'] #-> '2'
-
1
def [](name)
-
1015
attr = get_attribute(name)
-
1015
return attr.value unless attr.nil?
-
return nil
-
end
-
-
1
def to_a
-
values.flatten
-
end
-
-
# Returns the number of attributes the owning Element contains.
-
# doc = Document "<a x='1' y='2' foo:x='3'/>"
-
# doc.root.attributes.length #-> 3
-
1
def length
-
c = 0
-
each_attribute { c+=1 }
-
c
-
end
-
1
alias :size :length
-
-
# Iterates over the attributes of an Element. Yields actual Attribute
-
# nodes, not String values.
-
#
-
# doc = Document.new '<a x="1" y="2"/>'
-
# doc.root.attributes.each_attribute {|attr|
-
# p attr.expanded_name+" => "+attr.value
-
# }
-
1
def each_attribute # :yields: attribute
-
184
each_value do |val|
-
150
if val.kind_of? Attribute
-
150
yield val
-
else
-
val.each_value { |atr| yield atr }
-
end
-
end
-
end
-
-
# Iterates over each attribute of an Element, yielding the expanded name
-
# and value as a pair of Strings.
-
#
-
# doc = Document.new '<a x="1" y="2"/>'
-
# doc.root.attributes.each {|name, value| p name+" => "+value }
-
1
def each
-
184
each_attribute do |attr|
-
150
yield [attr.expanded_name, attr.value]
-
end
-
end
-
-
# Fetches an attribute
-
# name::
-
# the name by which to search for the attribute. Can be a
-
# <tt>prefix:name</tt> namespace name.
-
# Returns:: The first matching attribute, or nil if there was none. This
-
# value is an Attribute node, not the String value of the attribute.
-
# doc = Document.new '<a x:foo="1" foo="2" bar="3"/>'
-
# doc.root.attributes.get_attribute("foo").value #-> "2"
-
# doc.root.attributes.get_attribute("x:foo").value #-> "1"
-
1
def get_attribute( name )
-
1015
attr = fetch( name, nil )
-
1015
if attr.nil?
-
1007
return nil if name.nil?
-
# Look for prefix
-
1007
name =~ Namespace::NAMESPLIT
-
1007
prefix, n = $1, $2
-
1007
if prefix
-
attr = fetch( n, nil )
-
# check prefix
-
if attr == nil
-
elsif attr.kind_of? Attribute
-
return attr if prefix == attr.prefix
-
else
-
attr = attr[ prefix ]
-
return attr
-
end
-
end
-
1007
element_document = @element.document
-
1007
if element_document and element_document.doctype
-
expn = @element.expanded_name
-
expn = element_document.doctype.name if expn.size == 0
-
attr_val = element_document.doctype.attribute_of(expn, name)
-
return Attribute.new( name, attr_val ) if attr_val
-
end
-
1007
return nil
-
end
-
8
if attr.kind_of? Hash
-
attr = attr[ @element.prefix ]
-
end
-
8
return attr
-
end
-
-
# Sets an attribute, overwriting any existing attribute value by the
-
# same name. Namespace is significant.
-
# name:: the name of the attribute
-
# value::
-
# (optional) If supplied, the value of the attribute. If
-
# nil, any existing matching attribute is deleted.
-
# Returns::
-
# Owning element
-
# doc = Document.new "<a x:foo='1' foo='3'/>"
-
# doc.root.attributes['y:foo'] = '2'
-
# doc.root.attributes['foo'] = '4'
-
# doc.root.attributes['x:foo'] = nil
-
1
def []=( name, value )
-
163
if value.nil? # Delete the named attribute
-
attr = get_attribute(name)
-
delete attr
-
return
-
end
-
-
163
unless value.kind_of? Attribute
-
if @element.document and @element.document.doctype
-
value = Text::normalize( value, @element.document.doctype )
-
else
-
value = Text::normalize( value, nil )
-
end
-
value = Attribute.new(name, value)
-
end
-
163
value.element = @element
-
163
old_attr = fetch(value.name, nil)
-
163
if old_attr.nil?
-
163
store(value.name, value)
-
elsif old_attr.kind_of? Hash
-
old_attr[value.prefix] = value
-
elsif old_attr.prefix != value.prefix
-
# Check for conflicting namespaces
-
raise ParseException.new(
-
"Namespace conflict in adding attribute \"#{value.name}\": "+
-
"Prefix \"#{old_attr.prefix}\" = "+
-
"\"#{@element.namespace(old_attr.prefix)}\" and prefix "+
-
"\"#{value.prefix}\" = \"#{@element.namespace(value.prefix)}\"") if
-
value.prefix != "xmlns" and old_attr.prefix != "xmlns" and
-
@element.namespace( old_attr.prefix ) ==
-
@element.namespace( value.prefix )
-
store value.name, { old_attr.prefix => old_attr,
-
value.prefix => value }
-
else
-
store value.name, value
-
end
-
163
return @element
-
end
-
-
# Returns an array of Strings containing all of the prefixes declared
-
# by this set of # attributes. The array does not include the default
-
# namespace declaration, if one exists.
-
# doc = Document.new("<a xmlns='foo' xmlns:x='bar' xmlns:y='twee' "+
-
# "z='glorp' p:k='gru'/>")
-
# prefixes = doc.root.attributes.prefixes #-> ['x', 'y']
-
1
def prefixes
-
ns = []
-
each_attribute do |attribute|
-
ns << attribute.name if attribute.prefix == 'xmlns'
-
end
-
if @element.document and @element.document.doctype
-
expn = @element.expanded_name
-
expn = @element.document.doctype.name if expn.size == 0
-
@element.document.doctype.attributes_of(expn).each {
-
|attribute|
-
ns << attribute.name if attribute.prefix == 'xmlns'
-
}
-
end
-
ns
-
end
-
-
1
def namespaces
-
namespaces = {}
-
each_attribute do |attribute|
-
namespaces[attribute.name] = attribute.value if attribute.prefix == 'xmlns' or attribute.name == 'xmlns'
-
end
-
if @element.document and @element.document.doctype
-
expn = @element.expanded_name
-
expn = @element.document.doctype.name if expn.size == 0
-
@element.document.doctype.attributes_of(expn).each {
-
|attribute|
-
namespaces[attribute.name] = attribute.value if attribute.prefix == 'xmlns' or attribute.name == 'xmlns'
-
}
-
end
-
namespaces
-
end
-
-
# Removes an attribute
-
# attribute::
-
# either a String, which is the name of the attribute to remove --
-
# namespaces are significant here -- or the attribute to remove.
-
# Returns:: the owning element
-
# doc = Document.new "<a y:foo='0' x:foo='1' foo='3' z:foo='4'/>"
-
# doc.root.attributes.delete 'foo' #-> <a y:foo='0' x:foo='1' z:foo='4'/>"
-
# doc.root.attributes.delete 'x:foo' #-> <a y:foo='0' z:foo='4'/>"
-
# attr = doc.root.attributes.get_attribute('y:foo')
-
# doc.root.attributes.delete attr #-> <a z:foo='4'/>"
-
1
def delete( attribute )
-
name = nil
-
prefix = nil
-
if attribute.kind_of? Attribute
-
name = attribute.name
-
prefix = attribute.prefix
-
else
-
attribute =~ Namespace::NAMESPLIT
-
prefix, name = $1, $2
-
prefix = '' unless prefix
-
end
-
old = fetch(name, nil)
-
attr = nil
-
if old.kind_of? Hash # the supplied attribute is one of many
-
attr = old.delete(prefix)
-
if old.size == 1
-
repl = nil
-
old.each_value{|v| repl = v}
-
store name, repl
-
end
-
elsif old.nil?
-
return @element
-
else # the supplied attribute is a top-level one
-
attr = old
-
super(name)
-
end
-
@element
-
end
-
-
# Adds an attribute, overriding any existing attribute by the
-
# same name. Namespaces are significant.
-
# attribute:: An Attribute
-
1
def add( attribute )
-
self[attribute.name] = attribute
-
end
-
-
1
alias :<< :add
-
-
# Deletes all attributes matching a name. Namespaces are significant.
-
# name::
-
# A String; all attributes that match this path will be removed
-
# Returns:: an Array of the Attributes that were removed
-
1
def delete_all( name )
-
rv = []
-
each_attribute { |attribute|
-
rv << attribute if attribute.expanded_name == name
-
}
-
rv.each{ |attr| attr.remove }
-
return rv
-
end
-
-
# The +get_attribute_ns+ method retrieves a method by its namespace
-
# and name. Thus it is possible to reliably identify an attribute
-
# even if an XML processor has changed the prefix.
-
#
-
# Method contributed by Henrik Martensson
-
1
def get_attribute_ns(namespace, name)
-
result = nil
-
each_attribute() { |attribute|
-
if name == attribute.name &&
-
namespace == attribute.namespace() &&
-
( !namespace.empty? || !attribute.fully_expanded_name.index(':') )
-
# foo will match xmlns:foo, but only if foo isn't also an attribute
-
result = attribute if !result or !namespace.empty? or
-
!attribute.fully_expanded_name.index(':')
-
end
-
}
-
result
-
end
-
end
-
end
-
1
module REXML
-
1
module Encoding
-
# ID ---> Encoding name
-
1
attr_reader :encoding
-
1
def encoding=(encoding)
-
28
encoding = encoding.name if encoding.is_a?(Encoding)
-
28
if encoding.is_a?(String)
-
28
original_encoding = encoding
-
28
encoding = find_encoding(encoding)
-
28
unless encoding
-
raise ArgumentError, "Bad encoding name #{original_encoding}"
-
end
-
end
-
28
return false if defined?(@encoding) and encoding == @encoding
-
19
if encoding
-
19
@encoding = encoding.upcase
-
else
-
@encoding = 'UTF-8'
-
end
-
19
true
-
end
-
-
1
def check_encoding(xml)
-
# We have to recognize UTF-16BE, UTF-16LE, and UTF-8
-
9
if xml[0, 2] == "\xfe\xff"
-
xml[0, 2] = ""
-
return 'UTF-16BE'
-
elsif xml[0, 2] == "\xff\xfe"
-
xml[0, 2] = ""
-
return 'UTF-16LE'
-
end
-
9
xml =~ /^\s*<\?xml\s+version\s*=\s*(['"]).*?\1\s+encoding\s*=\s*(["'])(.*?)\2/m
-
9
return $3 ? $3.upcase : 'UTF-8'
-
end
-
-
1
def encode(string)
-
9
string.encode(@encoding)
-
end
-
-
1
def decode(string)
-
string.encode(::Encoding::UTF_8, @encoding)
-
end
-
-
1
private
-
1
def find_encoding(name)
-
28
case name
-
when /\Ashift-jis\z/i
-
return "SHIFT_JIS"
-
when /\ACP-(\d+)\z/
-
name = "CP#{$1}"
-
when /\AUTF-8\z/i
-
28
return name
-
end
-
begin
-
::Encoding::Converter.search_convpath(name, 'UTF-8')
-
rescue ::Encoding::ConverterNotFoundError
-
return nil
-
end
-
name
-
end
-
end
-
end
-
1
require 'rexml/child'
-
1
require 'rexml/source'
-
1
require 'rexml/xmltokens'
-
-
1
module REXML
-
# God, I hate DTDs. I really do. Why this idiot standard still
-
# plagues us is beyond me.
-
1
class Entity < Child
-
1
include XMLTokens
-
1
PUBIDCHAR = "\x20\x0D\x0Aa-zA-Z0-9\\-()+,./:=?;!*@$_%#"
-
1
SYSTEMLITERAL = %Q{((?:"[^"]*")|(?:'[^']*'))}
-
1
PUBIDLITERAL = %Q{("[#{PUBIDCHAR}']*"|'[#{PUBIDCHAR}]*')}
-
1
EXTERNALID = "(?:(?:(SYSTEM)\\s+#{SYSTEMLITERAL})|(?:(PUBLIC)\\s+#{PUBIDLITERAL}\\s+#{SYSTEMLITERAL}))"
-
1
NDATADECL = "\\s+NDATA\\s+#{NAME}"
-
1
PEREFERENCE = "%#{NAME};"
-
1
ENTITYVALUE = %Q{((?:"(?:[^%&"]|#{PEREFERENCE}|#{REFERENCE})*")|(?:'([^%&']|#{PEREFERENCE}|#{REFERENCE})*'))}
-
1
PEDEF = "(?:#{ENTITYVALUE}|#{EXTERNALID})"
-
1
ENTITYDEF = "(?:#{ENTITYVALUE}|(?:#{EXTERNALID}(#{NDATADECL})?))"
-
1
PEDECL = "<!ENTITY\\s+(%)\\s+#{NAME}\\s+#{PEDEF}\\s*>"
-
1
GEDECL = "<!ENTITY\\s+#{NAME}\\s+#{ENTITYDEF}\\s*>"
-
1
ENTITYDECL = /\s*(?:#{GEDECL})|(?:#{PEDECL})/um
-
-
1
attr_reader :name, :external, :ref, :ndata, :pubid
-
-
# Create a new entity. Simple entities can be constructed by passing a
-
# name, value to the constructor; this creates a generic, plain entity
-
# reference. For anything more complicated, you have to pass a Source to
-
# the constructor with the entity definition, or use the accessor methods.
-
# +WARNING+: There is no validation of entity state except when the entity
-
# is read from a stream. If you start poking around with the accessors,
-
# you can easily create a non-conformant Entity. The best thing to do is
-
# dump the stupid DTDs and use XMLSchema instead.
-
#
-
# e = Entity.new( 'amp', '&' )
-
1
def initialize stream, value=nil, parent=nil, reference=false
-
5
super(parent)
-
5
@ndata = @pubid = @value = @external = nil
-
5
if stream.kind_of? Array
-
@name = stream[1]
-
if stream[-1] == '%'
-
@reference = true
-
stream.pop
-
else
-
@reference = false
-
end
-
if stream[2] =~ /SYSTEM|PUBLIC/
-
@external = stream[2]
-
if @external == 'SYSTEM'
-
@ref = stream[3]
-
@ndata = stream[4] if stream.size == 5
-
else
-
@pubid = stream[3]
-
@ref = stream[4]
-
end
-
else
-
@value = stream[2]
-
end
-
else
-
5
@reference = reference
-
5
@external = nil
-
5
@name = stream
-
5
@value = value
-
end
-
end
-
-
# Evaluates whether the given string matchs an entity definition,
-
# returning true if so, and false otherwise.
-
1
def Entity::matches? string
-
(ENTITYDECL =~ string) == 0
-
end
-
-
# Evaluates to the unnormalized value of this entity; that is, replacing
-
# all entities -- both %ent; and &ent; entities. This differs from
-
# +value()+ in that +value+ only replaces %ent; entities.
-
1
def unnormalized
-
document.record_entity_expansion unless document.nil?
-
v = value()
-
return nil if v.nil?
-
@unnormalized = Text::unnormalize(v, parent)
-
@unnormalized
-
end
-
-
#once :unnormalized
-
-
# Returns the value of this entity unprocessed -- raw. This is the
-
# normalized value; that is, with all %ent; and &ent; entities intact
-
1
def normalized
-
@value
-
end
-
-
# Write out a fully formed, correct entity definition (assuming the Entity
-
# object itself is valid.)
-
#
-
# out::
-
# An object implementing <TT><<<TT> to which the entity will be
-
# output
-
# indent::
-
# *DEPRECATED* and ignored
-
1
def write out, indent=-1
-
out << '<!ENTITY '
-
out << '% ' if @reference
-
out << @name
-
out << ' '
-
if @external
-
out << @external << ' '
-
if @pubid
-
q = @pubid.include?('"')?"'":'"'
-
out << q << @pubid << q << ' '
-
end
-
q = @ref.include?('"')?"'":'"'
-
out << q << @ref << q
-
out << ' NDATA ' << @ndata if @ndata
-
else
-
q = @value.include?('"')?"'":'"'
-
out << q << @value << q
-
end
-
out << '>'
-
end
-
-
# Returns this entity as a string. See write().
-
1
def to_s
-
rv = ''
-
write rv
-
rv
-
end
-
-
1
PEREFERENCE_RE = /#{PEREFERENCE}/um
-
# Returns the value of this entity. At the moment, only internal entities
-
# are processed. If the value contains internal references (IE,
-
# %blah;), those are replaced with their values. IE, if the doctype
-
# contains:
-
# <!ENTITY % foo "bar">
-
# <!ENTITY yada "nanoo %foo; nanoo>
-
# then:
-
# doctype.entity('yada').value #-> "nanoo bar nanoo"
-
1
def value
-
4
if @value
-
4
matches = @value.scan(PEREFERENCE_RE)
-
4
rv = @value.clone
-
4
if @parent
-
matches.each do |entity_reference|
-
entity_value = @parent.entity( entity_reference[0] )
-
rv.gsub!( /%#{entity_reference.join};/um, entity_value )
-
end
-
end
-
4
return rv
-
end
-
nil
-
end
-
end
-
-
# This is a set of entity constants -- the ones defined in the XML
-
# specification. These are +gt+, +lt+, +amp+, +quot+ and +apos+.
-
1
module EntityConst
-
# +>+
-
1
GT = Entity.new( 'gt', '>' )
-
# +<+
-
1
LT = Entity.new( 'lt', '<' )
-
# +&+
-
1
AMP = Entity.new( 'amp', '&' )
-
# +"+
-
1
QUOT = Entity.new( 'quot', '"' )
-
# +'+
-
1
APOS = Entity.new( 'apos', "'" )
-
end
-
end
-
1
module REXML
-
1
module Formatters
-
1
class Default
-
# Prints out the XML document with no formatting -- except if id_hack is
-
# set.
-
#
-
# ie_hack::
-
# If set to true, then inserts whitespace before the close of an empty
-
# tag, so that IE's bad XML parser doesn't choke.
-
1
def initialize( ie_hack=false )
-
@ie_hack = ie_hack
-
end
-
-
# Writes the node to some output.
-
#
-
# node::
-
# The node to write
-
# output::
-
# A class implementing <TT><<</TT>. Pass in an Output object to
-
# change the output encoding.
-
1
def write( node, output )
-
case node
-
-
when Document
-
if node.xml_decl.encoding != 'UTF-8' && !output.kind_of?(Output)
-
output = Output.new( output, node.xml_decl.encoding )
-
end
-
write_document( node, output )
-
-
when Element
-
write_element( node, output )
-
-
when Declaration, ElementDecl, NotationDecl, ExternalEntity, Entity,
-
Attribute, AttlistDecl
-
node.write( output,-1 )
-
-
when Instruction
-
write_instruction( node, output )
-
-
when DocType, XMLDecl
-
node.write( output )
-
-
when Comment
-
write_comment( node, output )
-
-
when CData
-
write_cdata( node, output )
-
-
when Text
-
write_text( node, output )
-
-
else
-
raise Exception.new("XML FORMATTING ERROR")
-
-
end
-
end
-
-
1
protected
-
1
def write_document( node, output )
-
node.children.each { |child| write( child, output ) }
-
end
-
-
1
def write_element( node, output )
-
output << "<#{node.expanded_name}"
-
-
node.attributes.to_a.map { |a|
-
Hash === a ? a.values : a
-
}.flatten.sort_by {|attr| attr.name}.each do |attr|
-
output << " "
-
attr.write( output )
-
end unless node.attributes.empty?
-
-
if node.children.empty?
-
output << " " if @ie_hack
-
output << "/"
-
else
-
output << ">"
-
node.children.each { |child|
-
write( child, output )
-
}
-
output << "</#{node.expanded_name}"
-
end
-
output << ">"
-
end
-
-
1
def write_text( node, output )
-
output << node.to_s()
-
end
-
-
1
def write_comment( node, output )
-
output << Comment::START
-
output << node.to_s
-
output << Comment::STOP
-
end
-
-
1
def write_cdata( node, output )
-
output << CData::START
-
output << node.to_s
-
output << CData::STOP
-
end
-
-
1
def write_instruction( node, output )
-
output << Instruction::START.sub(/\\/u, '')
-
output << node.target
-
output << ' '
-
output << node.content
-
output << Instruction::STOP.sub(/\\/u, '')
-
end
-
end
-
end
-
end
-
1
require 'rexml/formatters/default'
-
-
1
module REXML
-
1
module Formatters
-
# Pretty-prints an XML document. This destroys whitespace in text nodes
-
# and will insert carriage returns and indentations.
-
#
-
# TODO: Add an option to print attributes on new lines
-
1
class Pretty < Default
-
-
# If compact is set to true, then the formatter will attempt to use as
-
# little space as possible
-
1
attr_accessor :compact
-
# The width of a page. Used for formatting text
-
1
attr_accessor :width
-
-
# Create a new pretty printer.
-
#
-
# output::
-
# An object implementing '<<(String)', to which the output will be written.
-
# indentation::
-
# An integer greater than 0. The indentation of each level will be
-
# this number of spaces. If this is < 1, the behavior of this object
-
# is undefined. Defaults to 2.
-
# ie_hack::
-
# If true, the printer will insert whitespace before closing empty
-
# tags, thereby allowing Internet Explorer's feeble XML parser to
-
# function. Defaults to false.
-
1
def initialize( indentation=2, ie_hack=false )
-
@indentation = indentation
-
@level = 0
-
@ie_hack = ie_hack
-
@width = 80
-
@compact = false
-
end
-
-
1
protected
-
1
def write_element(node, output)
-
output << ' '*@level
-
output << "<#{node.expanded_name}"
-
-
node.attributes.each_attribute do |attr|
-
output << " "
-
attr.write( output )
-
end unless node.attributes.empty?
-
-
if node.children.empty?
-
if @ie_hack
-
output << " "
-
end
-
output << "/"
-
else
-
output << ">"
-
# If compact and all children are text, and if the formatted output
-
# is less than the specified width, then try to print everything on
-
# one line
-
skip = false
-
if compact
-
if node.children.inject(true) {|s,c| s & c.kind_of?(Text)}
-
string = ""
-
old_level = @level
-
@level = 0
-
node.children.each { |child| write( child, string ) }
-
@level = old_level
-
if string.length < @width
-
output << string
-
skip = true
-
end
-
end
-
end
-
unless skip
-
output << "\n"
-
@level += @indentation
-
node.children.each { |child|
-
next if child.kind_of?(Text) and child.to_s.strip.length == 0
-
write( child, output )
-
output << "\n"
-
}
-
@level -= @indentation
-
output << ' '*@level
-
end
-
output << "</#{node.expanded_name}"
-
end
-
output << ">"
-
end
-
-
1
def write_text( node, output )
-
s = node.to_s()
-
s.gsub!(/\s/,' ')
-
s.squeeze!(" ")
-
s = wrap(s, @width - @level)
-
s = indent_text(s, @level, " ", true)
-
output << (' '*@level + s)
-
end
-
-
1
def write_comment( node, output)
-
output << ' ' * @level
-
super
-
end
-
-
1
def write_cdata( node, output)
-
output << ' ' * @level
-
super
-
end
-
-
1
def write_document( node, output )
-
# Ok, this is a bit odd. All XML documents have an XML declaration,
-
# but it may not write itself if the user didn't specifically add it,
-
# either through the API or in the input document. If it doesn't write
-
# itself, then we don't need a carriage return... which makes this
-
# logic more complex.
-
node.children.each { |child|
-
next if child == node.children[-1] and child.instance_of?(Text)
-
unless child == node.children[0] or child.instance_of?(Text) or
-
(child == node.children[1] and !node.children[0].writethis)
-
output << "\n"
-
end
-
write( child, output )
-
}
-
end
-
-
1
private
-
1
def indent_text(string, level=1, style="\t", indentfirstline=true)
-
return string if level < 0
-
string.gsub(/\n/, "\n#{style*level}")
-
end
-
-
1
def wrap(string, width)
-
parts = []
-
while string.length > width and place = string.rindex(' ', width)
-
parts << string[0...place]
-
string = string[place+1..-1]
-
end
-
parts << string
-
parts.join("\n")
-
end
-
-
end
-
end
-
end
-
-
1
module REXML
-
# If you add a method, keep in mind two things:
-
# (1) the first argument will always be a list of nodes from which to
-
# filter. In the case of context methods (such as position), the function
-
# should return an array with a value for each child in the array.
-
# (2) all method calls from XML will have "-" replaced with "_".
-
# Therefore, in XML, "local-name()" is identical (and actually becomes)
-
# "local_name()"
-
1
module Functions
-
1
@@context = nil
-
1
@@namespace_context = {}
-
1
@@variables = {}
-
-
45
def Functions::namespace_context=(x) ; @@namespace_context=x ; end
-
45
def Functions::variables=(x) ; @@variables=x ; end
-
1
def Functions::namespace_context ; @@namespace_context ; end
-
1
def Functions::variables ; @@variables ; end
-
-
1
def Functions::context=(value); @@context = value; end
-
-
1
def Functions::text( )
-
if @@context[:node].node_type == :element
-
return @@context[:node].find_all{|n| n.node_type == :text}.collect{|n| n.value}
-
elsif @@context[:node].node_type == :text
-
return @@context[:node].value
-
else
-
return false
-
end
-
end
-
-
# Returns the last node of the given list of nodes.
-
1
def Functions::last( )
-
@@context[:size]
-
end
-
-
1
def Functions::position( )
-
@@context[:index]
-
end
-
-
# Returns the size of the given list of nodes.
-
1
def Functions::count( node_set )
-
node_set.size
-
end
-
-
# Since REXML is non-validating, this method is not implemented as it
-
# requires a DTD
-
1
def Functions::id( object )
-
end
-
-
# UNTESTED
-
1
def Functions::local_name( node_set=nil )
-
get_namespace( node_set ) do |node|
-
return node.local_name
-
end
-
end
-
-
1
def Functions::namespace_uri( node_set=nil )
-
get_namespace( node_set ) {|node| node.namespace}
-
end
-
-
1
def Functions::name( node_set=nil )
-
get_namespace( node_set ) do |node|
-
node.expanded_name
-
end
-
end
-
-
# Helper method.
-
1
def Functions::get_namespace( node_set = nil )
-
if node_set == nil
-
yield @@context[:node] if defined? @@context[:node].namespace
-
else
-
if node_set.respond_to? :each
-
node_set.each { |node| yield node if defined? node.namespace }
-
elsif node_set.respond_to? :namespace
-
yield node_set
-
end
-
end
-
end
-
-
# A node-set is converted to a string by returning the string-value of the
-
# node in the node-set that is first in document order. If the node-set is
-
# empty, an empty string is returned.
-
#
-
# A number is converted to a string as follows
-
#
-
# NaN is converted to the string NaN
-
#
-
# positive zero is converted to the string 0
-
#
-
# negative zero is converted to the string 0
-
#
-
# positive infinity is converted to the string Infinity
-
#
-
# negative infinity is converted to the string -Infinity
-
#
-
# if the number is an integer, the number is represented in decimal form
-
# as a Number with no decimal point and no leading zeros, preceded by a
-
# minus sign (-) if the number is negative
-
#
-
# otherwise, the number is represented in decimal form as a Number
-
# including a decimal point with at least one digit before the decimal
-
# point and at least one digit after the decimal point, preceded by a
-
# minus sign (-) if the number is negative; there must be no leading zeros
-
# before the decimal point apart possibly from the one required digit
-
# immediately before the decimal point; beyond the one required digit
-
# after the decimal point there must be as many, but only as many, more
-
# digits as are needed to uniquely distinguish the number from all other
-
# IEEE 754 numeric values.
-
#
-
# The boolean false value is converted to the string false. The boolean
-
# true value is converted to the string true.
-
#
-
# An object of a type other than the four basic types is converted to a
-
# string in a way that is dependent on that type.
-
1
def Functions::string( object=nil )
-
#object = @context unless object
-
if object.instance_of? Array
-
string( object[0] )
-
elsif defined? object.node_type
-
if object.node_type == :attribute
-
object.value
-
elsif object.node_type == :element || object.node_type == :document
-
string_value(object)
-
else
-
object.to_s
-
end
-
elsif object.nil?
-
return ""
-
else
-
object.to_s
-
end
-
end
-
-
# A node-set is converted to a string by
-
# returning the concatenation of the string-value
-
# of each of the children of the node in the
-
# node-set that is first in document order.
-
# If the node-set is empty, an empty string is returned.
-
1
def Functions::string_value( o )
-
rv = ""
-
o.children.each { |e|
-
if e.node_type == :text
-
rv << e.to_s
-
elsif e.node_type == :element
-
rv << string_value( e )
-
end
-
}
-
rv
-
end
-
-
# UNTESTED
-
1
def Functions::concat( *objects )
-
objects.join
-
end
-
-
# Fixed by Mike Stok
-
1
def Functions::starts_with( string, test )
-
string(string).index(string(test)) == 0
-
end
-
-
# Fixed by Mike Stok
-
1
def Functions::contains( string, test )
-
string(string).include?(string(test))
-
end
-
-
# Kouhei fixed this
-
1
def Functions::substring_before( string, test )
-
ruby_string = string(string)
-
ruby_index = ruby_string.index(string(test))
-
if ruby_index.nil?
-
""
-
else
-
ruby_string[ 0...ruby_index ]
-
end
-
end
-
-
# Kouhei fixed this too
-
1
def Functions::substring_after( string, test )
-
ruby_string = string(string)
-
return $1 if ruby_string =~ /#{test}(.*)/
-
""
-
end
-
-
# Take equal portions of Mike Stok and Sean Russell; mix
-
# vigorously, and pour into a tall, chilled glass. Serves 10,000.
-
1
def Functions::substring( string, start, length=nil )
-
ruby_string = string(string)
-
ruby_length = if length.nil?
-
ruby_string.length.to_f
-
else
-
number(length)
-
end
-
ruby_start = number(start)
-
-
# Handle the special cases
-
return '' if (
-
ruby_length.nan? or
-
ruby_start.nan? or
-
ruby_start.infinite?
-
)
-
-
infinite_length = ruby_length.infinite? == 1
-
ruby_length = ruby_string.length if infinite_length
-
-
# Now, get the bounds. The XPath bounds are 1..length; the ruby bounds
-
# are 0..length. Therefore, we have to offset the bounds by one.
-
ruby_start = ruby_start.round - 1
-
ruby_length = ruby_length.round
-
-
if ruby_start < 0
-
ruby_length += ruby_start unless infinite_length
-
ruby_start = 0
-
end
-
return '' if ruby_length <= 0
-
ruby_string[ruby_start,ruby_length]
-
end
-
-
# UNTESTED
-
1
def Functions::string_length( string )
-
string(string).length
-
end
-
-
# UNTESTED
-
1
def Functions::normalize_space( string=nil )
-
string = string(@@context[:node]) if string.nil?
-
if string.kind_of? Array
-
string.collect{|x| string.to_s.strip.gsub(/\s+/um, ' ') if string}
-
else
-
string.to_s.strip.gsub(/\s+/um, ' ')
-
end
-
end
-
-
# This is entirely Mike Stok's beast
-
1
def Functions::translate( string, tr1, tr2 )
-
from = string(tr1)
-
to = string(tr2)
-
-
# the map is our translation table.
-
#
-
# if a character occurs more than once in the
-
# from string then we ignore the second &
-
# subsequent mappings
-
#
-
# if a character maps to nil then we delete it
-
# in the output. This happens if the from
-
# string is longer than the to string
-
#
-
# there's nothing about - or ^ being special in
-
# http://www.w3.org/TR/xpath#function-translate
-
# so we don't build ranges or negated classes
-
-
map = Hash.new
-
0.upto(from.length - 1) { |pos|
-
from_char = from[pos]
-
unless map.has_key? from_char
-
map[from_char] =
-
if pos < to.length
-
to[pos]
-
else
-
nil
-
end
-
end
-
}
-
-
if ''.respond_to? :chars
-
string(string).chars.collect { |c|
-
if map.has_key? c then map[c] else c end
-
}.compact.join
-
else
-
string(string).unpack('U*').collect { |c|
-
if map.has_key? c then map[c] else c end
-
}.compact.pack('U*')
-
end
-
end
-
-
# UNTESTED
-
1
def Functions::boolean( object=nil )
-
if object.kind_of? String
-
if object =~ /\d+/u
-
return object.to_f != 0
-
else
-
return object.size > 0
-
end
-
elsif object.kind_of? Array
-
object = object.find{|x| x and true}
-
end
-
return object ? true : false
-
end
-
-
# UNTESTED
-
1
def Functions::not( object )
-
not boolean( object )
-
end
-
-
# UNTESTED
-
1
def Functions::true( )
-
true
-
end
-
-
# UNTESTED
-
1
def Functions::false( )
-
false
-
end
-
-
# UNTESTED
-
1
def Functions::lang( language )
-
lang = false
-
node = @@context[:node]
-
attr = nil
-
until node.nil?
-
if node.node_type == :element
-
attr = node.attributes["xml:lang"]
-
unless attr.nil?
-
lang = compare_language(string(language), attr)
-
break
-
else
-
end
-
end
-
node = node.parent
-
end
-
lang
-
end
-
-
1
def Functions::compare_language lang1, lang2
-
lang2.downcase.index(lang1.downcase) == 0
-
end
-
-
# a string that consists of optional whitespace followed by an optional
-
# minus sign followed by a Number followed by whitespace is converted to
-
# the IEEE 754 number that is nearest (according to the IEEE 754
-
# round-to-nearest rule) to the mathematical value represented by the
-
# string; any other string is converted to NaN
-
#
-
# boolean true is converted to 1; boolean false is converted to 0
-
#
-
# a node-set is first converted to a string as if by a call to the string
-
# function and then converted in the same way as a string argument
-
#
-
# an object of a type other than the four basic types is converted to a
-
# number in a way that is dependent on that type
-
1
def Functions::number( object=nil )
-
object = @@context[:node] unless object
-
case object
-
when true
-
Float(1)
-
when false
-
Float(0)
-
when Array
-
number(string( object ))
-
when Numeric
-
object.to_f
-
else
-
str = string( object )
-
# If XPath ever gets scientific notation...
-
#if str =~ /^\s*-?(\d*\.?\d+|\d+\.)([Ee]\d*)?\s*$/
-
if str =~ /^\s*-?(\d*\.?\d+|\d+\.)\s*$/
-
str.to_f
-
else
-
(0.0 / 0.0)
-
end
-
end
-
end
-
-
1
def Functions::sum( nodes )
-
nodes = [nodes] unless nodes.kind_of? Array
-
nodes.inject(0) { |r,n| r += number(string(n)) }
-
end
-
-
1
def Functions::floor( number )
-
number(number).floor
-
end
-
-
1
def Functions::ceiling( number )
-
number(number).ceil
-
end
-
-
1
def Functions::round( number )
-
begin
-
number(number).round
-
rescue FloatDomainError
-
number(number)
-
end
-
end
-
-
1
def Functions::processing_instruction( node )
-
node.node_type == :processing_instruction
-
end
-
-
1
def Functions::method_missing( id )
-
puts "METHOD MISSING #{id.id2name}"
-
XPath.match( @@context[:node], id.id2name )
-
end
-
end
-
end
-
1
require "rexml/child"
-
1
require "rexml/source"
-
-
1
module REXML
-
# Represents an XML Instruction; IE, <? ... ?>
-
# TODO: Add parent arg (3rd arg) to constructor
-
1
class Instruction < Child
-
1
START = '<\?'
-
1
STOP = '\?>'
-
-
# target is the "name" of the Instruction; IE, the "tag" in <?tag ...?>
-
# content is everything else.
-
1
attr_accessor :target, :content
-
-
# Constructs a new Instruction
-
# @param target can be one of a number of things. If String, then
-
# the target of this instruction is set to this. If an Instruction,
-
# then the Instruction is shallowly cloned (target and content are
-
# copied). If a Source, then the source is scanned and parsed for
-
# an Instruction declaration.
-
# @param content Must be either a String, or a Parent. Can only
-
# be a Parent if the target argument is a Source. Otherwise, this
-
# String is set as the content of this instruction.
-
1
def initialize(target, content=nil)
-
if target.kind_of? String
-
super()
-
@target = target
-
@content = content
-
elsif target.kind_of? Instruction
-
super(content)
-
@target = target.target
-
@content = target.content
-
end
-
@content.strip! if @content
-
end
-
-
1
def clone
-
Instruction.new self
-
end
-
-
# == DEPRECATED
-
# See the rexml/formatters package
-
#
-
1
def write writer, indent=-1, transitive=false, ie_hack=false
-
Kernel.warn( "#{self.class.name}.write is deprecated" )
-
indent(writer, indent)
-
writer << START.sub(/\\/u, '')
-
writer << @target
-
writer << ' '
-
writer << @content
-
writer << STOP.sub(/\\/u, '')
-
end
-
-
# @return true if other is an Instruction, and the content and target
-
# of the other matches the target and content of this object.
-
1
def ==( other )
-
other.kind_of? Instruction and
-
other.target == @target and
-
other.content == @content
-
end
-
-
1
def node_type
-
:processing_instruction
-
end
-
-
1
def inspect
-
"<?p-i #{target} ...?>"
-
end
-
end
-
end
-
1
require 'rexml/xmltokens'
-
-
1
module REXML
-
# Adds named attributes to an object.
-
1
module Namespace
-
# The name of the object, valid if set
-
1
attr_reader :name, :expanded_name
-
# The expanded name of the object, valid if name is set
-
1
attr_accessor :prefix
-
1
include XMLTokens
-
1
NAMESPLIT = /^(?:(#{NCNAME_STR}):)?(#{NCNAME_STR})/u
-
-
# Sets the name and the expanded name
-
1
def name=( name )
-
373
@expanded_name = name
-
373
name =~ NAMESPLIT
-
373
if $1
-
@prefix = $1
-
else
-
373
@prefix = ""
-
373
@namespace = ""
-
end
-
373
@name = $2
-
end
-
-
# Compares names optionally WITH namespaces
-
1
def has_name?( other, ns=nil )
-
if ns
-
return (namespace() == ns and name() == other)
-
elsif other.include? ":"
-
return fully_expanded_name == other
-
else
-
return name == other
-
end
-
end
-
-
1
alias :local_name :name
-
-
# Fully expand the name, even if the prefix wasn't specified in the
-
# source file.
-
1
def fully_expanded_name
-
ns = prefix
-
return "#{ns}:#@name" if ns.size > 0
-
return @name
-
end
-
end
-
end
-
1
require "rexml/parseexception"
-
1
require "rexml/formatters/pretty"
-
1
require "rexml/formatters/default"
-
-
1
module REXML
-
# Represents a node in the tree. Nodes are never encountered except as
-
# superclasses of other objects. Nodes have siblings.
-
1
module Node
-
# @return the next sibling (nil if unset)
-
1
def next_sibling_node
-
return nil if @parent.nil?
-
@parent[ @parent.index(self) + 1 ]
-
end
-
-
# @return the previous sibling (nil if unset)
-
1
def previous_sibling_node
-
return nil if @parent.nil?
-
ind = @parent.index(self)
-
return nil if ind == 0
-
@parent[ ind - 1 ]
-
end
-
-
# indent::
-
# *DEPRECATED* This parameter is now ignored. See the formatters in the
-
# REXML::Formatters package for changing the output style.
-
1
def to_s indent=nil
-
unless indent.nil?
-
Kernel.warn( "#{self.class.name}.to_s(indent) parameter is deprecated" )
-
f = REXML::Formatters::Pretty.new( indent )
-
f.write( self, rv = "" )
-
else
-
f = REXML::Formatters::Default.new
-
f.write( self, rv = "" )
-
end
-
return rv
-
end
-
-
1
def indent to, ind
-
if @parent and @parent.context and not @parent.context[:indentstyle].nil? then
-
indentstyle = @parent.context[:indentstyle]
-
else
-
indentstyle = ' '
-
end
-
to << indentstyle*ind unless ind<1
-
end
-
-
1
def parent?
-
false;
-
end
-
-
-
# Visit all subnodes of +self+ recursively
-
1
def each_recursive(&block) # :yields: node
-
self.elements.each {|node|
-
block.call(node)
-
node.each_recursive(&block)
-
}
-
end
-
-
# Find (and return) first subnode (recursively) for which the block
-
# evaluates to true. Returns +nil+ if none was found.
-
1
def find_first_recursive(&block) # :yields: node
-
each_recursive {|node|
-
return node if block.call(node)
-
}
-
return nil
-
end
-
-
# Returns the position that +self+ holds in its parent's array, indexed
-
# from 1.
-
1
def index_in_parent
-
parent.index(self)+1
-
end
-
end
-
end
-
1
require 'rexml/encoding'
-
-
1
module REXML
-
1
class Output
-
1
include Encoding
-
-
1
attr_reader :encoding
-
-
1
def initialize real_IO, encd="iso-8859-1"
-
@output = real_IO
-
self.encoding = encd
-
-
@to_utf = encd != 'UTF-8'
-
end
-
-
1
def <<( content )
-
@output << (@to_utf ? self.encode(content) : content)
-
end
-
-
1
def to_s
-
"Output[#{encoding}]"
-
end
-
end
-
end
-
1
require "rexml/child"
-
-
1
module REXML
-
# A parent has children, and has methods for accessing them. The Parent
-
# class is never encountered except as the superclass for some other
-
# object.
-
1
class Parent < Child
-
1
include Enumerable
-
-
# Constructor
-
# @param parent if supplied, will be set as the parent of this object
-
1
def initialize parent=nil
-
210
super(parent)
-
210
@children = []
-
end
-
-
1
def add( object )
-
#puts "PARENT GOTS #{size} CHILDREN"
-
575
object.parent = self
-
575
@children << object
-
#puts "PARENT NOW GOTS #{size} CHILDREN"
-
575
object
-
end
-
-
1
alias :push :add
-
1
alias :<< :push
-
-
1
def unshift( object )
-
object.parent = self
-
@children.unshift object
-
end
-
-
1
def delete( object )
-
found = false
-
@children.delete_if {|c| c.equal?(object) and found = true }
-
object.parent = nil if found
-
found ? object : nil
-
end
-
-
1
def each(&block)
-
763
@children.each(&block)
-
end
-
-
1
def delete_if( &block )
-
@children.delete_if(&block)
-
end
-
-
1
def delete_at( index )
-
@children.delete_at index
-
end
-
-
1
def each_index( &block )
-
@children.each_index(&block)
-
end
-
-
# Fetches a child at a given index
-
# @param index the Integer index of the child to fetch
-
1
def []( index )
-
374
@children[index]
-
end
-
-
1
alias :each_child :each
-
-
-
-
# Set an index entry. See Array.[]=
-
# @param index the index of the element to set
-
# @param opt either the object to set, or an Integer length
-
# @param child if opt is an Integer, this is the child to set
-
# @return the parent (self)
-
1
def []=( *args )
-
args[-1].parent = self
-
@children[*args[0..-2]] = args[-1]
-
end
-
-
# Inserts an child before another child
-
# @param child1 this is either an xpath or an Element. If an Element,
-
# child2 will be inserted before child1 in the child list of the parent.
-
# If an xpath, child2 will be inserted before the first child to match
-
# the xpath.
-
# @param child2 the child to insert
-
# @return the parent (self)
-
1
def insert_before( child1, child2 )
-
if child1.kind_of? String
-
child1 = XPath.first( self, child1 )
-
child1.parent.insert_before child1, child2
-
else
-
ind = index(child1)
-
child2.parent.delete(child2) if child2.parent
-
@children[ind,0] = child2
-
child2.parent = self
-
end
-
self
-
end
-
-
# Inserts an child after another child
-
# @param child1 this is either an xpath or an Element. If an Element,
-
# child2 will be inserted after child1 in the child list of the parent.
-
# If an xpath, child2 will be inserted after the first child to match
-
# the xpath.
-
# @param child2 the child to insert
-
# @return the parent (self)
-
1
def insert_after( child1, child2 )
-
if child1.kind_of? String
-
child1 = XPath.first( self, child1 )
-
child1.parent.insert_after child1, child2
-
else
-
ind = index(child1)+1
-
child2.parent.delete(child2) if child2.parent
-
@children[ind,0] = child2
-
child2.parent = self
-
end
-
self
-
end
-
-
1
def to_a
-
975
@children.dup
-
end
-
-
# Fetches the index of a given child
-
# @param child the child to get the index of
-
# @return the index of the child, or nil if the object is not a child
-
# of this parent.
-
1
def index( child )
-
19
count = -1
-
152
@children.find { |i| count += 1 ; i.hash == child.hash }
-
19
count
-
end
-
-
# @return the number of children of this parent
-
1
def size
-
@children.size
-
end
-
-
1
alias :length :size
-
-
# Replaces one child with another, making sure the nodelist is correct
-
# @param to_replace the child to replace (must be a Child)
-
# @param replacement the child to insert into the nodelist (must be a
-
# Child)
-
1
def replace_child( to_replace, replacement )
-
@children.map! {|c| c.equal?( to_replace ) ? replacement : c }
-
to_replace.parent = nil
-
replacement.parent = self
-
end
-
-
# Deeply clones this object. This creates a complete duplicate of this
-
# Parent, including all descendants.
-
1
def deep_clone
-
cl = clone()
-
each do |child|
-
if child.kind_of? Parent
-
cl << child.deep_clone
-
else
-
cl << child.clone
-
end
-
end
-
cl
-
end
-
-
1
alias :children :to_a
-
-
1
def parent?
-
true
-
end
-
end
-
end
-
1
module REXML
-
1
class ParseException < RuntimeError
-
1
attr_accessor :source, :parser, :continued_exception
-
-
1
def initialize( message, source=nil, parser=nil, exception=nil )
-
super(message)
-
@source = source
-
@parser = parser
-
@continued_exception = exception
-
end
-
-
1
def to_s
-
# Quote the original exception, if there was one
-
if @continued_exception
-
err = @continued_exception.inspect
-
err << "\n"
-
err << @continued_exception.backtrace.join("\n")
-
err << "\n...\n"
-
else
-
err = ""
-
end
-
-
# Get the stack trace and error message
-
err << super
-
-
# Add contextual information
-
if @source
-
err << "\nLine: #{line}\n"
-
err << "Position: #{position}\n"
-
err << "Last 80 unconsumed characters:\n"
-
err << @source.buffer[0..80].force_encoding("ASCII-8BIT").gsub(/\n/, ' ')
-
end
-
-
err
-
end
-
-
1
def position
-
@source.current_line[0] if @source and defined? @source.current_line and
-
@source.current_line
-
end
-
-
1
def line
-
@source.current_line[2] if @source and defined? @source.current_line and
-
@source.current_line
-
end
-
-
1
def context
-
@source.current_line
-
end
-
end
-
end
-
1
require 'rexml/parseexception'
-
1
require 'rexml/undefinednamespaceexception'
-
1
require 'rexml/source'
-
1
require 'set'
-
-
1
module REXML
-
1
module Parsers
-
# = Using the Pull Parser
-
# <em>This API is experimental, and subject to change.</em>
-
# parser = PullParser.new( "<a>text<b att='val'/>txet</a>" )
-
# while parser.has_next?
-
# res = parser.next
-
# puts res[1]['att'] if res.start_tag? and res[0] == 'b'
-
# end
-
# See the PullEvent class for information on the content of the results.
-
# The data is identical to the arguments passed for the various events to
-
# the StreamListener API.
-
#
-
# Notice that:
-
# parser = PullParser.new( "<a>BAD DOCUMENT" )
-
# while parser.has_next?
-
# res = parser.next
-
# raise res[1] if res.error?
-
# end
-
#
-
# Nat Price gave me some good ideas for the API.
-
1
class BaseParser
-
1
LETTER = '[:alpha:]'
-
1
DIGIT = '[:digit:]'
-
-
1
COMBININGCHAR = '' # TODO
-
1
EXTENDER = '' # TODO
-
-
1
NCNAME_STR= "[#{LETTER}_:][-[:alnum:]._:#{COMBININGCHAR}#{EXTENDER}]*"
-
1
NAME_STR= "(?:(#{NCNAME_STR}):)?(#{NCNAME_STR})"
-
1
UNAME_STR= "(?:#{NCNAME_STR}:)?#{NCNAME_STR}"
-
-
1
NAMECHAR = '[\-\w\.:]'
-
1
NAME = "([\\w:]#{NAMECHAR}*)"
-
1
NMTOKEN = "(?:#{NAMECHAR})+"
-
1
NMTOKENS = "#{NMTOKEN}(\\s+#{NMTOKEN})*"
-
1
REFERENCE = "&(?:#{NAME};|#\\d+;|#x[0-9a-fA-F]+;)"
-
1
REFERENCE_RE = /#{REFERENCE}/
-
-
1
DOCTYPE_START = /\A\s*<!DOCTYPE\s/um
-
1
DOCTYPE_PATTERN = /\s*<!DOCTYPE\s+(.*?)(\[|>)/um
-
1
ATTRIBUTE_PATTERN = /\s*(#{NAME_STR})\s*=\s*(["'])(.*?)\4/um
-
1
COMMENT_START = /\A<!--/u
-
1
COMMENT_PATTERN = /<!--(.*?)-->/um
-
1
CDATA_START = /\A<!\[CDATA\[/u
-
1
CDATA_END = /^\s*\]\s*>/um
-
1
CDATA_PATTERN = /<!\[CDATA\[(.*?)\]\]>/um
-
1
XMLDECL_START = /\A<\?xml\s/u;
-
1
XMLDECL_PATTERN = /<\?xml\s+(.*?)\?>/um
-
1
INSTRUCTION_START = /\A<\?/u
-
1
INSTRUCTION_PATTERN = /<\?(.*?)(\s+.*?)?\?>/um
-
1
TAG_MATCH = /^<((?>#{NAME_STR}))\s*((?>\s+#{UNAME_STR}\s*=\s*(["']).*?\5)*)\s*(\/)?>/um
-
1
CLOSE_MATCH = /^\s*<\/(#{NAME_STR})\s*>/um
-
-
1
VERSION = /\bversion\s*=\s*["'](.*?)['"]/um
-
1
ENCODING = /\bencoding\s*=\s*["'](.*?)['"]/um
-
1
STANDALONE = /\bstandalone\s*=\s*["'](.*?)['"]/um
-
-
1
ENTITY_START = /^\s*<!ENTITY/
-
1
IDENTITY = /^([!\*\w\-]+)(\s+#{NCNAME_STR})?(\s+["'](.*?)['"])?(\s+['"](.*?)["'])?/u
-
1
ELEMENTDECL_START = /^\s*<!ELEMENT/um
-
1
ELEMENTDECL_PATTERN = /^\s*(<!ELEMENT.*?)>/um
-
1
SYSTEMENTITY = /^\s*(%.*?;)\s*$/um
-
1
ENUMERATION = "\\(\\s*#{NMTOKEN}(?:\\s*\\|\\s*#{NMTOKEN})*\\s*\\)"
-
1
NOTATIONTYPE = "NOTATION\\s+\\(\\s*#{NAME}(?:\\s*\\|\\s*#{NAME})*\\s*\\)"
-
1
ENUMERATEDTYPE = "(?:(?:#{NOTATIONTYPE})|(?:#{ENUMERATION}))"
-
1
ATTTYPE = "(CDATA|ID|IDREF|IDREFS|ENTITY|ENTITIES|NMTOKEN|NMTOKENS|#{ENUMERATEDTYPE})"
-
1
ATTVALUE = "(?:\"((?:[^<&\"]|#{REFERENCE})*)\")|(?:'((?:[^<&']|#{REFERENCE})*)')"
-
1
DEFAULTDECL = "(#REQUIRED|#IMPLIED|(?:(#FIXED\\s+)?#{ATTVALUE}))"
-
1
ATTDEF = "\\s+#{NAME}\\s+#{ATTTYPE}\\s+#{DEFAULTDECL}"
-
1
ATTDEF_RE = /#{ATTDEF}/
-
1
ATTLISTDECL_START = /^\s*<!ATTLIST/um
-
1
ATTLISTDECL_PATTERN = /^\s*<!ATTLIST\s+#{NAME}(?:#{ATTDEF})*\s*>/um
-
1
NOTATIONDECL_START = /^\s*<!NOTATION/um
-
1
PUBLIC = /^\s*<!NOTATION\s+(\w[\-\w]*)\s+(PUBLIC)\s+(["'])(.*?)\3(?:\s+(["'])(.*?)\5)?\s*>/um
-
1
SYSTEM = /^\s*<!NOTATION\s+(\w[\-\w]*)\s+(SYSTEM)\s+(["'])(.*?)\3\s*>/um
-
-
1
TEXT_PATTERN = /\A([^<]*)/um
-
-
# Entity constants
-
1
PUBIDCHAR = "\x20\x0D\x0Aa-zA-Z0-9\\-()+,./:=?;!*@$_%#"
-
1
SYSTEMLITERAL = %Q{((?:"[^"]*")|(?:'[^']*'))}
-
1
PUBIDLITERAL = %Q{("[#{PUBIDCHAR}']*"|'[#{PUBIDCHAR}]*')}
-
1
EXTERNALID = "(?:(?:(SYSTEM)\\s+#{SYSTEMLITERAL})|(?:(PUBLIC)\\s+#{PUBIDLITERAL}\\s+#{SYSTEMLITERAL}))"
-
1
NDATADECL = "\\s+NDATA\\s+#{NAME}"
-
1
PEREFERENCE = "%#{NAME};"
-
1
ENTITYVALUE = %Q{((?:"(?:[^%&"]|#{PEREFERENCE}|#{REFERENCE})*")|(?:'([^%&']|#{PEREFERENCE}|#{REFERENCE})*'))}
-
1
PEDEF = "(?:#{ENTITYVALUE}|#{EXTERNALID})"
-
1
ENTITYDEF = "(?:#{ENTITYVALUE}|(?:#{EXTERNALID}(#{NDATADECL})?))"
-
1
PEDECL = "<!ENTITY\\s+(%)\\s+#{NAME}\\s+#{PEDEF}\\s*>"
-
1
GEDECL = "<!ENTITY\\s+#{NAME}\\s+#{ENTITYDEF}\\s*>"
-
1
ENTITYDECL = /\s*(?:#{GEDECL})|(?:#{PEDECL})/um
-
-
1
EREFERENCE = /&(?!#{NAME};)/
-
-
1
DEFAULT_ENTITIES = {
-
'gt' => [/>/, '>', '>', />/],
-
'lt' => [/</, '<', '<', /</],
-
'quot' => [/"/, '"', '"', /"/],
-
"apos" => [/'/, "'", "'", /'/]
-
}
-
-
-
######################################################################
-
# These are patterns to identify common markup errors, to make the
-
# error messages more informative.
-
######################################################################
-
1
MISSING_ATTRIBUTE_QUOTES = /^<#{NAME_STR}\s+#{NAME_STR}\s*=\s*[^"']/um
-
-
1
def initialize( source )
-
9
self.stream = source
-
end
-
-
1
def add_listener( listener )
-
if !defined?(@listeners) or !@listeners
-
@listeners = []
-
instance_eval <<-EOL
-
alias :_old_pull :pull
-
def pull
-
event = _old_pull
-
@listeners.each do |listener|
-
listener.receive event
-
end
-
event
-
end
-
EOL
-
end
-
@listeners << listener
-
end
-
-
1
attr_reader :source
-
-
1
def stream=( source )
-
9
@source = SourceFactory.create_from( source )
-
9
@closed = nil
-
9
@document_status = nil
-
9
@tags = []
-
9
@stack = []
-
9
@entities = []
-
9
@nsstack = []
-
end
-
-
1
def position
-
if @source.respond_to? :position
-
@source.position
-
else
-
# FIXME
-
0
-
end
-
end
-
-
# Returns true if there are no more events
-
1
def empty?
-
776
return (@source.empty? and @stack.empty?)
-
end
-
-
# Returns true if there are more events. Synonymous with !empty?
-
1
def has_next?
-
return !(@source.empty? and @stack.empty?)
-
end
-
-
# Push an event back on the head of the stream. This method
-
# has (theoretically) infinite depth.
-
1
def unshift token
-
@stack.unshift(token)
-
end
-
-
# Peek at the +depth+ event in the stack. The first element on the stack
-
# is at depth 0. If +depth+ is -1, will parse to the end of the input
-
# stream and return the last event, which is always :end_document.
-
# Be aware that this causes the stream to be parsed up to the +depth+
-
# event, so you can effectively pre-parse the entire document (pull the
-
# entire thing into memory) using this method.
-
1
def peek depth=0
-
raise %Q[Illegal argument "#{depth}"] if depth < -1
-
temp = []
-
if depth == -1
-
temp.push(pull()) until empty?
-
else
-
while @stack.size+temp.size < depth+1
-
temp.push(pull())
-
end
-
end
-
@stack += temp if temp.size > 0
-
@stack[depth]
-
end
-
-
# Returns the next event. This is a +PullEvent+ object.
-
1
def pull
-
794
if @closed
-
18
x, @closed = @closed, nil
-
18
return [ :end_element, x ]
-
end
-
776
return [ :end_document ] if empty?
-
767
return @stack.shift if @stack.size > 0
-
#STDERR.puts @source.encoding
-
767
@source.read if @source.buffer.size<2
-
#STDERR.puts "BUFFER = #{@source.buffer.inspect}"
-
767
if @document_status == nil
-
#@source.consume( /^\s*/um )
-
26
word = @source.match( /^((?:\s+)|(?:<[^>]*>))/um )
-
26
word = word[1] unless word.nil?
-
#STDERR.puts "WORD = #{word.inspect}"
-
26
case word
-
when COMMENT_START
-
return [ :comment, @source.match( COMMENT_PATTERN, true )[1] ]
-
when XMLDECL_START
-
#STDERR.puts "XMLDECL"
-
9
results = @source.match( XMLDECL_PATTERN, true )[1]
-
9
version = VERSION.match( results )
-
9
version = version[1] unless version.nil?
-
9
encoding = ENCODING.match(results)
-
9
encoding = encoding[1] unless encoding.nil?
-
9
@source.encoding = encoding
-
9
standalone = STANDALONE.match(results)
-
9
standalone = standalone[1] unless standalone.nil?
-
9
return [ :xmldecl, version, encoding, standalone ]
-
when INSTRUCTION_START
-
return [ :processing_instruction, *@source.match(INSTRUCTION_PATTERN, true)[1,2] ]
-
when DOCTYPE_START
-
md = @source.match( DOCTYPE_PATTERN, true )
-
@nsstack.unshift(curr_ns=Set.new)
-
identity = md[1]
-
close = md[2]
-
identity =~ IDENTITY
-
name = $1
-
raise REXML::ParseException.new("DOCTYPE is missing a name") if name.nil?
-
pub_sys = $2.nil? ? nil : $2.strip
-
long_name = $4.nil? ? nil : $4.strip
-
uri = $6.nil? ? nil : $6.strip
-
args = [ :start_doctype, name, pub_sys, long_name, uri ]
-
if close == ">"
-
@document_status = :after_doctype
-
@source.read if @source.buffer.size<2
-
md = @source.match(/^\s*/um, true)
-
@stack << [ :end_doctype ]
-
else
-
@document_status = :in_doctype
-
end
-
return args
-
when /^\s+/
-
else
-
9
@document_status = :after_doctype
-
9
@source.read if @source.buffer.size<2
-
9
md = @source.match(/\s*/um, true)
-
9
if @source.encoding == "UTF-8"
-
9
@source.buffer.force_encoding(::Encoding::UTF_8)
-
end
-
end
-
end
-
758
if @document_status == :in_doctype
-
md = @source.match(/\s*(.*?>)/um)
-
case md[1]
-
when SYSTEMENTITY
-
match = @source.match( SYSTEMENTITY, true )[1]
-
return [ :externalentity, match ]
-
-
when ELEMENTDECL_START
-
return [ :elementdecl, @source.match( ELEMENTDECL_PATTERN, true )[1] ]
-
-
when ENTITY_START
-
match = @source.match( ENTITYDECL, true ).to_a.compact
-
match[0] = :entitydecl
-
ref = false
-
if match[1] == '%'
-
ref = true
-
match.delete_at 1
-
end
-
# Now we have to sort out what kind of entity reference this is
-
if match[2] == 'SYSTEM'
-
# External reference
-
match[3] = match[3][1..-2] # PUBID
-
match.delete_at(4) if match.size > 4 # Chop out NDATA decl
-
# match is [ :entity, name, SYSTEM, pubid(, ndata)? ]
-
elsif match[2] == 'PUBLIC'
-
# External reference
-
match[3] = match[3][1..-2] # PUBID
-
match[4] = match[4][1..-2] # HREF
-
# match is [ :entity, name, PUBLIC, pubid, href ]
-
else
-
match[2] = match[2][1..-2]
-
match.pop if match.size == 4
-
# match is [ :entity, name, value ]
-
end
-
match << '%' if ref
-
return match
-
when ATTLISTDECL_START
-
md = @source.match( ATTLISTDECL_PATTERN, true )
-
raise REXML::ParseException.new( "Bad ATTLIST declaration!", @source ) if md.nil?
-
element = md[1]
-
contents = md[0]
-
-
pairs = {}
-
values = md[0].scan( ATTDEF_RE )
-
values.each do |attdef|
-
unless attdef[3] == "#IMPLIED"
-
attdef.compact!
-
val = attdef[3]
-
val = attdef[4] if val == "#FIXED "
-
pairs[attdef[0]] = val
-
if attdef[0] =~ /^xmlns:(.*)/
-
@nsstack[0] << $1
-
end
-
end
-
end
-
return [ :attlistdecl, element, pairs, contents ]
-
when NOTATIONDECL_START
-
md = nil
-
if @source.match( PUBLIC )
-
md = @source.match( PUBLIC, true )
-
vals = [md[1],md[2],md[4],md[6]]
-
elsif @source.match( SYSTEM )
-
md = @source.match( SYSTEM, true )
-
vals = [md[1],md[2],nil,md[4]]
-
else
-
raise REXML::ParseException.new( "error parsing notation: no matching pattern", @source )
-
end
-
return [ :notationdecl, *vals ]
-
when CDATA_END
-
@document_status = :after_doctype
-
@source.match( CDATA_END, true )
-
return [ :end_doctype ]
-
end
-
end
-
758
begin
-
758
if @source.buffer[0] == ?<
-
384
if @source.buffer[1] == ?/
-
183
@nsstack.shift
-
183
last_tag = @tags.pop
-
#md = @source.match_to_consume( '>', CLOSE_MATCH)
-
183
md = @source.match( CLOSE_MATCH, true )
-
raise REXML::ParseException.new( "Missing end tag for "+
-
"'#{last_tag}' (got \"#{md[1]}\")",
-
183
@source) unless last_tag == md[1]
-
183
return [ :end_element, last_tag ]
-
elsif @source.buffer[1] == ?!
-
md = @source.match(/\A(\s*[^>]*>)/um)
-
#STDERR.puts "SOURCE BUFFER = #{source.buffer}, #{source.buffer.size}"
-
raise REXML::ParseException.new("Malformed node", @source) unless md
-
if md[0][2] == ?-
-
md = @source.match( COMMENT_PATTERN, true )
-
-
case md[1]
-
when /--/, /-$/
-
raise REXML::ParseException.new("Malformed comment", @source)
-
end
-
-
return [ :comment, md[1] ] if md
-
else
-
md = @source.match( CDATA_PATTERN, true )
-
return [ :cdata, md[1] ] if md
-
end
-
raise REXML::ParseException.new( "Declarations can only occur "+
-
"in the doctype declaration.", @source)
-
elsif @source.buffer[1] == ??
-
md = @source.match( INSTRUCTION_PATTERN, true )
-
return [ :processing_instruction, md[1], md[2] ] if md
-
raise REXML::ParseException.new( "Bad instruction declaration",
-
@source)
-
else
-
# Get the next tag
-
201
md = @source.match(TAG_MATCH, true)
-
201
unless md
-
# Check for missing attribute quotes
-
raise REXML::ParseException.new("missing attribute quote", @source) if @source.match(MISSING_ATTRIBUTE_QUOTES )
-
raise REXML::ParseException.new("malformed XML: missing tag start", @source)
-
end
-
201
attributes = {}
-
201
prefixes = Set.new
-
201
prefixes << md[2] if md[2]
-
201
@nsstack.unshift(curr_ns=Set.new)
-
201
if md[4].size > 0
-
149
attrs = md[4].scan( ATTRIBUTE_PATTERN )
-
149
raise REXML::ParseException.new( "error parsing attributes: [#{attrs.join ', '}], excess = \"#$'\"", @source) if $' and $'.strip.size > 0
-
149
attrs.each { |a,b,c,d,e|
-
163
if b == "xmlns"
-
if c == "xml"
-
if d != "http://www.w3.org/XML/1998/namespace"
-
msg = "The 'xml' prefix must not be bound to any other namespace "+
-
"(http://www.w3.org/TR/REC-xml-names/#ns-decl)"
-
raise REXML::ParseException.new( msg, @source, self )
-
end
-
elsif c == "xmlns"
-
msg = "The 'xmlns' prefix must not be declared "+
-
"(http://www.w3.org/TR/REC-xml-names/#ns-decl)"
-
raise REXML::ParseException.new( msg, @source, self)
-
end
-
curr_ns << c
-
elsif b
-
prefixes << b unless b == "xml"
-
end
-
-
163
if attributes.has_key? a
-
msg = "Duplicate attribute #{a.inspect}"
-
raise REXML::ParseException.new( msg, @source, self)
-
end
-
-
163
attributes[a] = e
-
}
-
end
-
-
# Verify that all of the prefixes have been defined
-
201
for prefix in prefixes
-
unless @nsstack.find{|k| k.member?(prefix)}
-
raise UndefinedNamespaceException.new(prefix,@source,self)
-
end
-
end
-
-
201
if md[6]
-
18
@closed = md[1]
-
18
@nsstack.shift
-
else
-
183
@tags.push( md[1] )
-
end
-
201
return [ :start_element, md[1], attributes ]
-
end
-
else
-
374
md = @source.match( TEXT_PATTERN, true )
-
374
if md[0].length == 0
-
@source.match( /(\s+)/, true )
-
end
-
#STDERR.puts "GOT #{md[1].inspect}" unless md[0].length == 0
-
#return [ :text, "" ] if md[0].length == 0
-
# unnormalized = Text::unnormalize( md[1], self )
-
# return PullEvent.new( :text, md[1], unnormalized )
-
374
return [ :text, md[1] ]
-
end
-
rescue REXML::UndefinedNamespaceException
-
raise
-
rescue REXML::ParseException
-
raise
-
rescue Exception, NameError => error
-
raise REXML::ParseException.new( "Exception parsing",
-
@source, self, (error ? error : $!) )
-
end
-
return [ :dummy ]
-
end
-
-
1
def entity( reference, entities )
-
value = nil
-
value = entities[ reference ] if entities
-
if not value
-
value = DEFAULT_ENTITIES[ reference ]
-
value = value[2] if value
-
end
-
unnormalize( value, entities ) if value
-
end
-
-
# Escapes all possible entities
-
1
def normalize( input, entities=nil, entity_filter=nil )
-
copy = input.clone
-
# Doing it like this rather than in a loop improves the speed
-
copy.gsub!( EREFERENCE, '&' )
-
entities.each do |key, value|
-
copy.gsub!( value, "&#{key};" ) unless entity_filter and
-
entity_filter.include?(entity)
-
end if entities
-
copy.gsub!( EREFERENCE, '&' )
-
DEFAULT_ENTITIES.each do |key, value|
-
copy.gsub!( value[3], value[1] )
-
end
-
copy
-
end
-
-
# Unescapes all possible entities
-
1
def unnormalize( string, entities=nil, filter=nil )
-
rv = string.clone
-
rv.gsub!( /\r\n?/, "\n" )
-
matches = rv.scan( REFERENCE_RE )
-
return rv if matches.size == 0
-
rv.gsub!( /�*((?:\d+)|(?:x[a-fA-F0-9]+));/ ) {
-
m=$1
-
m = "0#{m}" if m[0] == ?x
-
[Integer(m)].pack('U*')
-
}
-
matches.collect!{|x|x[0]}.compact!
-
if matches.size > 0
-
matches.each do |entity_reference|
-
unless filter and filter.include?(entity_reference)
-
entity_value = entity( entity_reference, entities )
-
if entity_value
-
re = /&#{entity_reference};/
-
rv.gsub!( re, entity_value )
-
else
-
er = DEFAULT_ENTITIES[entity_reference]
-
rv.gsub!( er[0], er[2] ) if er
-
end
-
end
-
end
-
rv.gsub!( /&/, '&' )
-
end
-
rv
-
end
-
end
-
end
-
end
-
-
=begin
-
case event[0]
-
when :start_element
-
when :text
-
when :end_element
-
when :processing_instruction
-
when :cdata
-
when :comment
-
when :xmldecl
-
when :start_doctype
-
when :end_doctype
-
when :externalentity
-
when :elementdecl
-
when :entity
-
when :attlistdecl
-
when :notationdecl
-
when :end_doctype
-
end
-
=end
-
1
module REXML
-
1
module Parsers
-
1
class StreamParser
-
1
def initialize source, listener
-
@listener = listener
-
@parser = BaseParser.new( source )
-
end
-
-
1
def add_listener( listener )
-
@parser.add_listener( listener )
-
end
-
-
1
def parse
-
# entity string
-
while true
-
event = @parser.pull
-
case event[0]
-
when :end_document
-
return
-
when :start_element
-
attrs = event[2].each do |n, v|
-
event[2][n] = @parser.unnormalize( v )
-
end
-
@listener.tag_start( event[1], attrs )
-
when :end_element
-
@listener.tag_end( event[1] )
-
when :text
-
normalized = @parser.unnormalize( event[1] )
-
@listener.text( normalized )
-
when :processing_instruction
-
@listener.instruction( *event[1,2] )
-
when :start_doctype
-
@listener.doctype( *event[1..-1] )
-
when :end_doctype
-
# FIXME: remove this condition for milestone:3.2
-
@listener.doctype_end if @listener.respond_to? :doctype_end
-
when :comment, :attlistdecl, :cdata, :xmldecl, :elementdecl
-
@listener.send( event[0].to_s, *event[1..-1] )
-
when :entitydecl, :notationdecl
-
@listener.send( event[0].to_s, event[1..-1] )
-
end
-
end
-
end
-
end
-
end
-
end
-
1
require 'rexml/validation/validationexception'
-
1
require 'rexml/undefinednamespaceexception'
-
-
1
module REXML
-
1
module Parsers
-
1
class TreeParser
-
1
def initialize( source, build_context = Document.new )
-
9
@build_context = build_context
-
9
@parser = Parsers::BaseParser.new( source )
-
end
-
-
1
def add_listener( listener )
-
@parser.add_listener( listener )
-
end
-
-
1
def parse
-
9
tag_stack = []
-
9
in_doctype = false
-
9
entities = nil
-
9
begin
-
9
while true
-
794
event = @parser.pull
-
#STDERR.puts "TREEPARSER GOT #{event.inspect}"
-
794
case event[0]
-
when :end_document
-
9
unless tag_stack.empty?
-
#raise ParseException.new("No close tag for #{tag_stack.inspect}")
-
raise ParseException.new("No close tag for #{@build_context.xpath}")
-
end
-
9
return
-
when :start_element
-
201
tag_stack.push(event[1])
-
201
el = @build_context = @build_context.add_element( event[1] )
-
201
event[2].each do |key, value|
-
163
el.attributes[key]=Attribute.new(key,value,self)
-
end
-
when :end_element
-
201
tag_stack.pop
-
201
@build_context = @build_context.parent
-
when :text
-
374
if not in_doctype
-
374
if @build_context[-1].instance_of? Text
-
@build_context[-1] << event[1]
-
else
-
@build_context.add(
-
Text.new(event[1], @build_context.whitespace, nil, true)
-
) unless (
-
@build_context.ignore_whitespace_nodes and
-
374
event[1].strip.size==0
-
)
-
end
-
end
-
when :comment
-
c = Comment.new( event[1] )
-
@build_context.add( c )
-
when :cdata
-
c = CData.new( event[1] )
-
@build_context.add( c )
-
when :processing_instruction
-
@build_context.add( Instruction.new( event[1], event[2] ) )
-
when :end_doctype
-
in_doctype = false
-
entities.each { |k,v| entities[k] = @build_context.entities[k].value }
-
@build_context = @build_context.parent
-
when :start_doctype
-
doctype = DocType.new( event[1..-1], @build_context )
-
@build_context = doctype
-
entities = {}
-
in_doctype = true
-
when :attlistdecl
-
n = AttlistDecl.new( event[1..-1] )
-
@build_context.add( n )
-
when :externalentity
-
n = ExternalEntity.new( event[1] )
-
@build_context.add( n )
-
when :elementdecl
-
n = ElementDecl.new( event[1] )
-
@build_context.add(n)
-
when :entitydecl
-
entities[ event[1] ] = event[2] unless event[2] =~ /PUBLIC|SYSTEM/
-
@build_context.add(Entity.new(event))
-
when :notationdecl
-
n = NotationDecl.new( *event[1..-1] )
-
@build_context.add( n )
-
when :xmldecl
-
9
x = XMLDecl.new( event[1], event[2], event[3] )
-
9
@build_context.add( x )
-
end
-
end
-
rescue REXML::Validation::ValidationException
-
raise
-
rescue REXML::UndefinedNamespaceException
-
raise
-
rescue
-
raise ParseException.new( $!.message, @parser.source, @parser, $! )
-
end
-
end
-
end
-
end
-
end
-
1
require 'rexml/namespace'
-
1
require 'rexml/xmltokens'
-
-
1
module REXML
-
1
module Parsers
-
# You don't want to use this class. Really. Use XPath, which is a wrapper
-
# for this class. Believe me. You don't want to poke around in here.
-
# There is strange, dark magic at work in this code. Beware. Go back! Go
-
# back while you still can!
-
1
class XPathParser
-
1
include XMLTokens
-
1
LITERAL = /^'([^']*)'|^"([^"]*)"/u
-
-
1
def namespaces=( namespaces )
-
Functions::namespace_context = namespaces
-
@namespaces = namespaces
-
end
-
-
1
def parse path
-
44
path = path.dup
-
44
path.gsub!(/([\(\[])\s+/, '\1') # Strip ignorable spaces
-
44
path.gsub!( /\s+([\]\)])/, '\1')
-
44
parsed = []
-
44
path = OrExpr(path, parsed)
-
44
parsed
-
end
-
-
1
def predicate path
-
parsed = []
-
Predicate( "[#{path}]", parsed )
-
parsed
-
end
-
-
1
def abbreviate( path )
-
path = path.kind_of?(String) ? parse( path ) : path
-
string = ""
-
document = false
-
while path.size > 0
-
op = path.shift
-
case op
-
when :node
-
when :attribute
-
string << "/" if string.size > 0
-
string << "@"
-
when :child
-
string << "/" if string.size > 0
-
when :descendant_or_self
-
string << "/"
-
when :self
-
string << "."
-
when :parent
-
string << ".."
-
when :any
-
string << "*"
-
when :text
-
string << "text()"
-
when :following, :following_sibling,
-
:ancestor, :ancestor_or_self, :descendant,
-
:namespace, :preceding, :preceding_sibling
-
string << "/" unless string.size == 0
-
string << op.to_s.tr("_", "-")
-
string << "::"
-
when :qname
-
prefix = path.shift
-
name = path.shift
-
string << prefix+":" if prefix.size > 0
-
string << name
-
when :predicate
-
string << '['
-
string << predicate_to_string( path.shift ) {|x| abbreviate( x ) }
-
string << ']'
-
when :document
-
document = true
-
when :function
-
string << path.shift
-
string << "( "
-
string << predicate_to_string( path.shift[0] ) {|x| abbreviate( x )}
-
string << " )"
-
when :literal
-
string << %Q{ "#{path.shift}" }
-
else
-
string << "/" unless string.size == 0
-
string << "UNKNOWN("
-
string << op.inspect
-
string << ")"
-
end
-
end
-
string = "/"+string if document
-
return string
-
end
-
-
1
def expand( path )
-
path = path.kind_of?(String) ? parse( path ) : path
-
string = ""
-
document = false
-
while path.size > 0
-
op = path.shift
-
case op
-
when :node
-
string << "node()"
-
when :attribute, :child, :following, :following_sibling,
-
:ancestor, :ancestor_or_self, :descendant, :descendant_or_self,
-
:namespace, :preceding, :preceding_sibling, :self, :parent
-
string << "/" unless string.size == 0
-
string << op.to_s.tr("_", "-")
-
string << "::"
-
when :any
-
string << "*"
-
when :qname
-
prefix = path.shift
-
name = path.shift
-
string << prefix+":" if prefix.size > 0
-
string << name
-
when :predicate
-
string << '['
-
string << predicate_to_string( path.shift ) { |x| expand(x) }
-
string << ']'
-
when :document
-
document = true
-
else
-
string << "/" unless string.size == 0
-
string << "UNKNOWN("
-
string << op.inspect
-
string << ")"
-
end
-
end
-
string = "/"+string if document
-
return string
-
end
-
-
1
def predicate_to_string( path, &block )
-
string = ""
-
case path[0]
-
when :and, :or, :mult, :plus, :minus, :neq, :eq, :lt, :gt, :lteq, :gteq, :div, :mod, :union
-
op = path.shift
-
case op
-
when :eq
-
op = "="
-
when :lt
-
op = "<"
-
when :gt
-
op = ">"
-
when :lteq
-
op = "<="
-
when :gteq
-
op = ">="
-
when :neq
-
op = "!="
-
when :union
-
op = "|"
-
end
-
left = predicate_to_string( path.shift, &block )
-
right = predicate_to_string( path.shift, &block )
-
string << " "
-
string << left
-
string << " "
-
string << op.to_s
-
string << " "
-
string << right
-
string << " "
-
when :function
-
path.shift
-
name = path.shift
-
string << name
-
string << "( "
-
string << predicate_to_string( path.shift, &block )
-
string << " )"
-
when :literal
-
path.shift
-
string << " "
-
string << path.shift.inspect
-
string << " "
-
else
-
string << " "
-
string << yield( path )
-
string << " "
-
end
-
return string.squeeze(" ")
-
end
-
-
1
private
-
#LocationPath
-
# | RelativeLocationPath
-
# | '/' RelativeLocationPath?
-
# | '//' RelativeLocationPath
-
1
def LocationPath path, parsed
-
#puts "LocationPath '#{path}'"
-
44
path = path.strip
-
44
if path[0] == ?/
-
19
parsed << :document
-
19
if path[1] == ?/
-
19
parsed << :descendant_or_self
-
19
parsed << :node
-
19
path = path[2..-1]
-
else
-
path = path[1..-1]
-
end
-
end
-
#puts parsed.inspect
-
44
return RelativeLocationPath( path, parsed ) if path.size > 0
-
end
-
-
#RelativeLocationPath
-
# | Step
-
# | (AXIS_NAME '::' | '@' | '') AxisSpecifier
-
# NodeTest
-
# Predicate
-
# | '.' | '..' AbbreviatedStep
-
# | RelativeLocationPath '/' Step
-
# | RelativeLocationPath '//' Step
-
1
AXIS = /^(ancestor|ancestor-or-self|attribute|child|descendant|descendant-or-self|following|following-sibling|namespace|parent|preceding|preceding-sibling|self)::/
-
1
def RelativeLocationPath path, parsed
-
#puts "RelativeLocationPath #{path}"
-
44
while path.size > 0
-
# (axis or @ or <child::>) nodetest predicate >
-
# OR > / Step
-
# (. or ..) >
-
44
if path[0] == ?.
-
if path[1] == ?.
-
parsed << :parent
-
parsed << :node
-
path = path[2..-1]
-
else
-
parsed << :self
-
parsed << :node
-
path = path[1..-1]
-
end
-
else
-
44
if path[0] == ?@
-
#puts "ATTRIBUTE"
-
parsed << :attribute
-
path = path[1..-1]
-
# Goto Nodetest
-
elsif path =~ AXIS
-
parsed << $1.tr('-','_').intern
-
path = $'
-
# Goto Nodetest
-
else
-
44
parsed << :child
-
end
-
-
#puts "NODETESTING '#{path}'"
-
44
n = []
-
44
path = NodeTest( path, n)
-
#puts "NODETEST RETURNED '#{path}'"
-
-
44
if path[0] == ?[
-
path = Predicate( path, n )
-
end
-
-
44
parsed.concat(n)
-
end
-
-
44
if path.size > 0
-
if path[0] == ?/
-
if path[1] == ?/
-
parsed << :descendant_or_self
-
parsed << :node
-
path = path[2..-1]
-
else
-
path = path[1..-1]
-
end
-
else
-
return path
-
end
-
end
-
end
-
44
return path
-
end
-
-
# Returns a 1-1 map of the nodeset
-
# The contents of the resulting array are either:
-
# true/false, if a positive match
-
# String, if a name match
-
#NodeTest
-
# | ('*' | NCNAME ':' '*' | QNAME) NameTest
-
# | NODE_TYPE '(' ')' NodeType
-
# | PI '(' LITERAL ')' PI
-
# | '[' expr ']' Predicate
-
1
NCNAMETEST= /^(#{NCNAME_STR}):\*/u
-
1
QNAME = Namespace::NAMESPLIT
-
1
NODE_TYPE = /^(comment|text|node)\(\s*\)/m
-
1
PI = /^processing-instruction\(/
-
1
def NodeTest path, parsed
-
#puts "NodeTest with #{path}"
-
44
case path
-
when /^\*/
-
25
path = $'
-
25
parsed << :any
-
when NODE_TYPE
-
type = $1
-
path = $'
-
parsed << type.tr('-', '_').intern
-
when PI
-
path = $'
-
literal = nil
-
if path !~ /^\s*\)/
-
path =~ LITERAL
-
literal = $1
-
path = $'
-
raise ParseException.new("Missing ')' after processing instruction") if path[0] != ?)
-
path = path[1..-1]
-
end
-
parsed << :processing_instruction
-
parsed << (literal || '')
-
when NCNAMETEST
-
#puts "NCNAMETEST"
-
prefix = $1
-
path = $'
-
parsed << :namespace
-
parsed << prefix
-
when QNAME
-
#puts "QNAME"
-
19
prefix = $1
-
19
name = $2
-
19
path = $'
-
19
prefix = "" unless prefix
-
19
parsed << :qname
-
19
parsed << prefix
-
19
parsed << name
-
end
-
44
return path
-
end
-
-
# Filters the supplied nodeset on the predicate(s)
-
1
def Predicate path, parsed
-
#puts "PREDICATE with #{path}"
-
return nil unless path[0] == ?[
-
predicates = []
-
while path[0] == ?[
-
path, expr = get_group(path)
-
predicates << expr[1..-2] if expr
-
end
-
#puts "PREDICATES = #{predicates.inspect}"
-
predicates.each{ |pred|
-
#puts "ORING #{pred}"
-
preds = []
-
parsed << :predicate
-
parsed << preds
-
OrExpr(pred, preds)
-
}
-
#puts "PREDICATES = #{predicates.inspect}"
-
path
-
end
-
-
# The following return arrays of true/false, a 1-1 mapping of the
-
# supplied nodeset, except for axe(), which returns a filtered
-
# nodeset
-
-
#| OrExpr S 'or' S AndExpr
-
#| AndExpr
-
1
def OrExpr path, parsed
-
#puts "OR >>> #{path}"
-
44
n = []
-
44
rest = AndExpr( path, n )
-
#puts "OR <<< #{rest}"
-
44
if rest != path
-
44
while rest =~ /^\s*( or )/
-
n = [ :or, n, [] ]
-
rest = AndExpr( $', n[-1] )
-
end
-
end
-
44
if parsed.size == 0 and n.size != 0
-
44
parsed.replace(n)
-
elsif n.size > 0
-
parsed << n
-
end
-
44
rest
-
end
-
-
#| AndExpr S 'and' S EqualityExpr
-
#| EqualityExpr
-
1
def AndExpr path, parsed
-
#puts "AND >>> #{path}"
-
44
n = []
-
44
rest = EqualityExpr( path, n )
-
#puts "AND <<< #{rest}"
-
44
if rest != path
-
44
while rest =~ /^\s*( and )/
-
n = [ :and, n, [] ]
-
#puts "AND >>> #{rest}"
-
rest = EqualityExpr( $', n[-1] )
-
#puts "AND <<< #{rest}"
-
end
-
end
-
44
if parsed.size == 0 and n.size != 0
-
44
parsed.replace(n)
-
elsif n.size > 0
-
parsed << n
-
end
-
44
rest
-
end
-
-
#| EqualityExpr ('=' | '!=') RelationalExpr
-
#| RelationalExpr
-
1
def EqualityExpr path, parsed
-
#puts "EQUALITY >>> #{path}"
-
44
n = []
-
44
rest = RelationalExpr( path, n )
-
#puts "EQUALITY <<< #{rest}"
-
44
if rest != path
-
44
while rest =~ /^\s*(!?=)\s*/
-
if $1[0] == ?!
-
n = [ :neq, n, [] ]
-
else
-
n = [ :eq, n, [] ]
-
end
-
rest = RelationalExpr( $', n[-1] )
-
end
-
end
-
44
if parsed.size == 0 and n.size != 0
-
44
parsed.replace(n)
-
elsif n.size > 0
-
parsed << n
-
end
-
44
rest
-
end
-
-
#| RelationalExpr ('<' | '>' | '<=' | '>=') AdditiveExpr
-
#| AdditiveExpr
-
1
def RelationalExpr path, parsed
-
#puts "RELATION >>> #{path}"
-
44
n = []
-
44
rest = AdditiveExpr( path, n )
-
#puts "RELATION <<< #{rest}"
-
44
if rest != path
-
44
while rest =~ /^\s*([<>]=?)\s*/
-
if $1[0] == ?<
-
sym = "lt"
-
else
-
sym = "gt"
-
end
-
sym << "eq" if $1[-1] == ?=
-
n = [ sym.intern, n, [] ]
-
rest = AdditiveExpr( $', n[-1] )
-
end
-
end
-
44
if parsed.size == 0 and n.size != 0
-
44
parsed.replace(n)
-
elsif n.size > 0
-
parsed << n
-
end
-
44
rest
-
end
-
-
#| AdditiveExpr ('+' | S '-') MultiplicativeExpr
-
#| MultiplicativeExpr
-
1
def AdditiveExpr path, parsed
-
#puts "ADDITIVE >>> #{path}"
-
44
n = []
-
44
rest = MultiplicativeExpr( path, n )
-
#puts "ADDITIVE <<< #{rest}"
-
44
if rest != path
-
44
while rest =~ /^\s*(\+| -)\s*/
-
if $1[0] == ?+
-
n = [ :plus, n, [] ]
-
else
-
n = [ :minus, n, [] ]
-
end
-
rest = MultiplicativeExpr( $', n[-1] )
-
end
-
end
-
44
if parsed.size == 0 and n.size != 0
-
44
parsed.replace(n)
-
elsif n.size > 0
-
parsed << n
-
end
-
44
rest
-
end
-
-
#| MultiplicativeExpr ('*' | S ('div' | 'mod') S) UnaryExpr
-
#| UnaryExpr
-
1
def MultiplicativeExpr path, parsed
-
#puts "MULT >>> #{path}"
-
44
n = []
-
44
rest = UnaryExpr( path, n )
-
#puts "MULT <<< #{rest}"
-
44
if rest != path
-
44
while rest =~ /^\s*(\*| div | mod )\s*/
-
if $1[0] == ?*
-
n = [ :mult, n, [] ]
-
elsif $1.include?( "div" )
-
n = [ :div, n, [] ]
-
else
-
n = [ :mod, n, [] ]
-
end
-
rest = UnaryExpr( $', n[-1] )
-
end
-
end
-
44
if parsed.size == 0 and n.size != 0
-
44
parsed.replace(n)
-
elsif n.size > 0
-
parsed << n
-
end
-
44
rest
-
end
-
-
#| '-' UnaryExpr
-
#| UnionExpr
-
1
def UnaryExpr path, parsed
-
44
path =~ /^(\-*)/
-
44
path = $'
-
44
if $1 and (($1.size % 2) != 0)
-
mult = -1
-
else
-
44
mult = 1
-
end
-
44
parsed << :neg if mult < 0
-
-
#puts "UNARY >>> #{path}"
-
44
n = []
-
44
path = UnionExpr( path, n )
-
#puts "UNARY <<< #{path}"
-
44
parsed.concat( n )
-
44
path
-
end
-
-
#| UnionExpr '|' PathExpr
-
#| PathExpr
-
1
def UnionExpr path, parsed
-
#puts "UNION >>> #{path}"
-
44
n = []
-
44
rest = PathExpr( path, n )
-
#puts "UNION <<< #{rest}"
-
44
if rest != path
-
44
while rest =~ /^\s*(\|)\s*/
-
n = [ :union, n, [] ]
-
rest = PathExpr( $', n[-1] )
-
end
-
end
-
44
if parsed.size == 0 and n.size != 0
-
44
parsed.replace( n )
-
elsif n.size > 0
-
parsed << n
-
end
-
44
rest
-
end
-
-
#| LocationPath
-
#| FilterExpr ('/' | '//') RelativeLocationPath
-
1
def PathExpr path, parsed
-
44
path =~ /^\s*/
-
44
path = $'
-
#puts "PATH >>> #{path}"
-
44
n = []
-
44
rest = FilterExpr( path, n )
-
#puts "PATH <<< '#{rest}'"
-
44
if rest != path
-
if rest and rest[0] == ?/
-
return RelativeLocationPath(rest, n)
-
end
-
end
-
#puts "BEFORE WITH '#{rest}'"
-
44
rest = LocationPath(rest, n) if rest =~ /\A[\/\.\@\[\w*]/
-
44
parsed.concat(n)
-
44
return rest
-
end
-
-
#| FilterExpr Predicate
-
#| PrimaryExpr
-
1
def FilterExpr path, parsed
-
#puts "FILTER >>> #{path}"
-
44
n = []
-
44
path = PrimaryExpr( path, n )
-
#puts "FILTER <<< #{path}"
-
44
path = Predicate(path, n) if path and path[0] == ?[
-
#puts "FILTER <<< #{path}"
-
44
parsed.concat(n)
-
44
path
-
end
-
-
#| VARIABLE_REFERENCE
-
#| '(' expr ')'
-
#| LITERAL
-
#| NUMBER
-
#| FunctionCall
-
1
VARIABLE_REFERENCE = /^\$(#{NAME_STR})/u
-
1
NUMBER = /^(\d*\.?\d+)/
-
1
NT = /^comment|text|processing-instruction|node$/
-
1
def PrimaryExpr path, parsed
-
44
case path
-
when VARIABLE_REFERENCE
-
varname = $1
-
path = $'
-
parsed << :variable
-
parsed << varname
-
#arry << @variables[ varname ]
-
when /^(\w[-\w]*)(?:\()/
-
#puts "PrimaryExpr :: Function >>> #$1 -- '#$''"
-
fname = $1
-
tmp = $'
-
#puts "#{fname} =~ #{NT.inspect}"
-
return path if fname =~ NT
-
path = tmp
-
parsed << :function
-
parsed << fname
-
path = FunctionCall(path, parsed)
-
when NUMBER
-
#puts "LITERAL or NUMBER: #$1"
-
varname = $1.nil? ? $2 : $1
-
path = $'
-
parsed << :literal
-
parsed << (varname.include?('.') ? varname.to_f : varname.to_i)
-
when LITERAL
-
#puts "LITERAL or NUMBER: #$1"
-
varname = $1.nil? ? $2 : $1
-
path = $'
-
parsed << :literal
-
parsed << varname
-
when /^\(/ #/
-
path, contents = get_group(path)
-
contents = contents[1..-2]
-
n = []
-
OrExpr( contents, n )
-
parsed.concat(n)
-
end
-
44
path
-
end
-
-
#| FUNCTION_NAME '(' ( expr ( ',' expr )* )? ')'
-
1
def FunctionCall rest, parsed
-
path, arguments = parse_args(rest)
-
argset = []
-
for argument in arguments
-
args = []
-
OrExpr( argument, args )
-
argset << args
-
end
-
parsed << argset
-
path
-
end
-
-
# get_group( '[foo]bar' ) -> ['bar', '[foo]']
-
1
def get_group string
-
ind = 0
-
depth = 0
-
st = string[0,1]
-
en = (st == "(" ? ")" : "]")
-
begin
-
case string[ind,1]
-
when st
-
depth += 1
-
when en
-
depth -= 1
-
end
-
ind += 1
-
end while depth > 0 and ind < string.length
-
return nil unless depth==0
-
[string[ind..-1], string[0..ind-1]]
-
end
-
-
1
def parse_args( string )
-
arguments = []
-
ind = 0
-
inquot = false
-
inapos = false
-
depth = 1
-
begin
-
case string[ind]
-
when ?"
-
inquot = !inquot unless inapos
-
when ?'
-
inapos = !inapos unless inquot
-
else
-
unless inquot or inapos
-
case string[ind]
-
when ?(
-
depth += 1
-
if depth == 1
-
string = string[1..-1]
-
ind -= 1
-
end
-
when ?)
-
depth -= 1
-
if depth == 0
-
s = string[0,ind].strip
-
arguments << s unless s == ""
-
string = string[ind+1..-1]
-
end
-
when ?,
-
if depth == 1
-
s = string[0,ind].strip
-
arguments << s unless s == ""
-
string = string[ind+1..-1]
-
ind = -1
-
end
-
end
-
end
-
end
-
ind += 1
-
end while depth > 0 and ind < string.length
-
return nil unless depth==0
-
[string,arguments]
-
end
-
end
-
end
-
end
-
# -*- encoding: utf-8 -*-
-
# REXML is an XML toolkit for Ruby[http://www.ruby-lang.org], in Ruby.
-
#
-
# REXML is a _pure_ Ruby, XML 1.0 conforming,
-
# non-validating[http://www.w3.org/TR/2004/REC-xml-20040204/#sec-conformance]
-
# toolkit with an intuitive API. REXML passes 100% of the non-validating Oasis
-
# tests[http://www.oasis-open.org/committees/xml-conformance/xml-test-suite.shtml],
-
# and provides tree, stream, SAX2, pull, and lightweight APIs. REXML also
-
# includes a full XPath[http://www.w3c.org/tr/xpath] 1.0 implementation. Since
-
# Ruby 1.8, REXML is included in the standard Ruby distribution.
-
#
-
# Main page:: http://www.germane-software.com/software/rexml
-
# Author:: Sean Russell <serATgermaneHYPHENsoftwareDOTcom>
-
# Date:: 2008/019
-
# Version:: 3.1.7.3
-
#
-
# This API documentation can be downloaded from the REXML home page, or can
-
# be accessed online[http://www.germane-software.com/software/rexml_doc]
-
#
-
# A tutorial is available in the REXML distribution in docs/tutorial.html,
-
# or can be accessed
-
# online[http://www.germane-software.com/software/rexml/docs/tutorial.html]
-
1
module REXML
-
1
COPYRIGHT = "Copyright © 2001-2008 Sean Russell <ser@germane-software.com>"
-
1
DATE = "2008/019"
-
1
VERSION = "3.1.7.3"
-
1
REVISION = %w$Revision: 26193 $[1] || ''
-
-
1
Copyright = COPYRIGHT
-
1
Version = VERSION
-
end
-
1
require 'rexml/encoding'
-
-
1
module REXML
-
# Generates Source-s. USE THIS CLASS.
-
1
class SourceFactory
-
# Generates a Source object
-
# @param arg Either a String, or an IO
-
# @return a Source, or nil if a bad argument was given
-
1
def SourceFactory::create_from(arg)
-
if arg.respond_to? :read and
-
9
arg.respond_to? :readline and
-
arg.respond_to? :nil? and
-
arg.respond_to? :eof?
-
8
IOSource.new(arg)
-
1
elsif arg.respond_to? :to_str
-
1
require 'stringio'
-
1
IOSource.new(StringIO.new(arg))
-
elsif arg.kind_of? Source
-
arg
-
else
-
raise "#{arg.class} is not a valid input stream. It must walk \n"+
-
"like either a String, an IO, or a Source."
-
end
-
end
-
end
-
-
# A Source can be searched for patterns, and wraps buffers and other
-
# objects and provides consumption of text
-
1
class Source
-
1
include Encoding
-
# The current buffer (what we're going to read next)
-
1
attr_reader :buffer
-
# The line number of the last consumed text
-
1
attr_reader :line
-
1
attr_reader :encoding
-
-
# Constructor
-
# @param arg must be a String, and should be a valid XML document
-
# @param encoding if non-null, sets the encoding of the source to this
-
# value, overriding all encoding detection
-
1
def initialize(arg, encoding=nil)
-
9
@orig = @buffer = arg
-
9
if encoding
-
self.encoding = encoding
-
else
-
9
self.encoding = check_encoding( @buffer )
-
end
-
9
@line = 0
-
end
-
-
-
# Inherited from Encoding
-
# Overridden to support optimized en/decoding
-
1
def encoding=(enc)
-
18
return unless super
-
9
@line_break = encode( '>' )
-
9
if @encoding != 'UTF-8'
-
@buffer = decode(@buffer)
-
@to_utf = true
-
else
-
9
@to_utf = false
-
9
@buffer.force_encoding ::Encoding::UTF_8
-
end
-
end
-
-
# Scans the source for a given pattern. Note, that this is not your
-
# usual scan() method. For one thing, the pattern argument has some
-
# requirements; for another, the source can be consumed. You can easily
-
# confuse this method. Originally, the patterns were easier
-
# to construct and this method more robust, because this method
-
# generated search regexes on the fly; however, this was
-
# computationally expensive and slowed down the entire REXML package
-
# considerably, since this is by far the most commonly called method.
-
# @param pattern must be a Regexp, and must be in the form of
-
# /^\s*(#{your pattern, with no groups})(.*)/. The first group
-
# will be returned; the second group is used if the consume flag is
-
# set.
-
# @param consume if true, the pattern returned will be consumed, leaving
-
# everything after it in the Source.
-
# @return the pattern, if found, or nil if the Source is empty or the
-
# pattern is not found.
-
1
def scan(pattern, cons=false)
-
return nil if @buffer.nil?
-
rv = @buffer.scan(pattern)
-
@buffer = $' if cons and rv.size>0
-
rv
-
end
-
-
1
def read
-
end
-
-
1
def consume( pattern )
-
@buffer = $' if pattern.match( @buffer )
-
end
-
-
1
def match_to( char, pattern )
-
return pattern.match(@buffer)
-
end
-
-
1
def match_to_consume( char, pattern )
-
md = pattern.match(@buffer)
-
@buffer = $'
-
return md
-
end
-
-
1
def match(pattern, cons=false)
-
md = pattern.match(@buffer)
-
@buffer = $' if cons and md
-
return md
-
end
-
-
# @return true if the Source is exhausted
-
1
def empty?
-
776
@buffer == ""
-
end
-
-
1
def position
-
@orig.index( @buffer )
-
end
-
-
# @return the current line in the source
-
1
def current_line
-
lines = @orig.split
-
res = lines.grep @buffer[0..30]
-
res = res[-1] if res.kind_of? Array
-
lines.index( res ) if res
-
end
-
end
-
-
# A Source that wraps an IO. See the Source class for method
-
# documentation
-
1
class IOSource < Source
-
#attr_reader :block_size
-
-
# block_size has been deprecated
-
1
def initialize(arg, block_size=500, encoding=nil)
-
9
@er_source = @source = arg
-
9
@to_utf = false
-
-
# Determining the encoding is a deceptively difficult issue to resolve.
-
# First, we check the first two bytes for UTF-16. Then we
-
# assume that the encoding is at least ASCII enough for the '>', and
-
# we read until we get one of those. This gives us the XML declaration,
-
# if there is one. If there isn't one, the file MUST be UTF-8, as per
-
# the XML spec. If there is one, we can determine the encoding from
-
# it.
-
9
@buffer = ""
-
9
str = @source.read( 2 ) || ''
-
9
if encoding
-
self.encoding = encoding
-
elsif str[0,2] == "\xfe\xff"
-
@line_break = "\000>"
-
elsif str[0,2] == "\xff\xfe"
-
@line_break = ">\000"
-
elsif str[0,2] == "\xef\xbb"
-
str += @source.read(1)
-
str = '' if (str[2,1] == "\xBF")
-
@line_break = ">"
-
else
-
9
@line_break = ">"
-
end
-
9
super( @source.eof? ? str : str+@source.readline( @line_break ) )
-
-
if !@to_utf and
-
9
@buffer.respond_to?(:force_encoding) and
-
@source.respond_to?(:external_encoding) and
-
@source.external_encoding != ::Encoding::UTF_8
-
9
@force_utf8 = true
-
else
-
@force_utf8 = false
-
end
-
end
-
-
1
def scan(pattern, cons=false)
-
rv = super
-
# You'll notice that this next section is very similar to the same
-
# section in match(), but just a liiittle different. This is
-
# because it is a touch faster to do it this way with scan()
-
# than the way match() does it; enough faster to warrent duplicating
-
# some code
-
if rv.size == 0
-
until @buffer =~ pattern or @source.nil?
-
begin
-
@buffer << readline
-
rescue Iconv::IllegalSequence
-
raise
-
rescue
-
@source = nil
-
end
-
end
-
rv = super
-
end
-
rv.taint
-
rv
-
end
-
-
1
def read
-
392
begin
-
392
@buffer << readline
-
rescue Exception, NameError
-
@source = nil
-
end
-
end
-
-
1
def consume( pattern )
-
match( pattern, true )
-
end
-
-
1
def match( pattern, cons=false )
-
802
rv = pattern.match(@buffer)
-
802
@buffer = $' if cons and rv
-
802
while !rv and @source
-
begin
-
@buffer << readline
-
rv = pattern.match(@buffer)
-
@buffer = $' if cons and rv
-
rescue
-
@source = nil
-
end
-
end
-
802
rv.taint
-
802
rv
-
end
-
-
1
def empty?
-
776
super and ( @source.nil? || @source.eof? )
-
end
-
-
1
def position
-
@er_source.pos rescue 0
-
end
-
-
# @return the current line in the source
-
1
def current_line
-
begin
-
pos = @er_source.pos # The byte position in the source
-
lineno = @er_source.lineno # The XML < position in the source
-
@er_source.rewind
-
line = 0 # The \r\n position in the source
-
begin
-
while @er_source.pos < pos
-
@er_source.readline
-
line += 1
-
end
-
rescue
-
end
-
rescue IOError
-
pos = -1
-
line = -1
-
end
-
[pos, lineno, line]
-
end
-
-
1
private
-
1
def readline
-
392
str = @source.readline(@line_break)
-
392
return nil if str.nil?
-
-
392
if @to_utf
-
decode(str)
-
else
-
392
str.force_encoding(::Encoding::UTF_8) if @force_utf8
-
392
str
-
end
-
end
-
end
-
end
-
1
module REXML
-
1
class SyncEnumerator
-
1
include Enumerable
-
-
# Creates a new SyncEnumerator which enumerates rows of given
-
# Enumerable objects.
-
1
def initialize(*enums)
-
@gens = enums
-
@length = @gens.collect {|x| x.size }.max
-
end
-
-
# Returns the number of enumerated Enumerable objects, i.e. the size
-
# of each row.
-
1
def size
-
@gens.size
-
end
-
-
# Returns the number of enumerated Enumerable objects, i.e. the size
-
# of each row.
-
1
def length
-
@gens.length
-
end
-
-
# Enumerates rows of the Enumerable objects.
-
1
def each
-
@length.times {|i|
-
yield @gens.collect {|x| x[i]}
-
}
-
self
-
end
-
end
-
end
-
1
require 'rexml/entity'
-
1
require 'rexml/doctype'
-
1
require 'rexml/child'
-
1
require 'rexml/doctype'
-
1
require 'rexml/parseexception'
-
-
1
module REXML
-
# Represents text nodes in an XML document
-
1
class Text < Child
-
1
include Comparable
-
# The order in which the substitutions occur
-
1
SPECIALS = [ /&(?!#?[\w-]+;)/u, /</u, />/u, /"/u, /'/u, /\r/u ]
-
1
SUBSTITUTES = ['&', '<', '>', '"', ''', ' ']
-
# Characters which are substituted in written strings
-
1
SLAICEPS = [ '<', '>', '"', "'", '&' ]
-
1
SETUTITSBUS = [ /</u, />/u, /"/u, /'/u, /&/u ]
-
-
# If +raw+ is true, then REXML leaves the value alone
-
1
attr_accessor :raw
-
-
1
NEEDS_A_SECOND_CHECK = /(<|&((#{Entity::NAME});|(#0*((?:\d+)|(?:x[a-fA-F0-9]+)));)?)/um
-
1
NUMERICENTITY = /�*((?:\d+)|(?:x[a-fA-F0-9]+));/
-
1
VALID_CHAR = [
-
0x9, 0xA, 0xD,
-
(0x20..0xD7FF),
-
(0xE000..0xFFFD),
-
(0x10000..0x10FFFF)
-
]
-
-
1
if String.method_defined? :encode
-
1
VALID_XML_CHARS = Regexp.new('^['+
-
VALID_CHAR.map { |item|
-
6
case item
-
when Fixnum
-
3
[item].pack('U').force_encoding('utf-8')
-
when Range
-
3
[item.first, '-'.ord, item.last].pack('UUU').force_encoding('utf-8')
-
end
-
}.join +
-
']*$')
-
else
-
VALID_XML_CHARS = /^(
-
[\x09\x0A\x0D\x20-\x7E] # ASCII
-
| [\xC2-\xDF][\x80-\xBF] # non-overlong 2-byte
-
| \xE0[\xA0-\xBF][\x80-\xBF] # excluding overlongs
-
| [\xE1-\xEC\xEE][\x80-\xBF]{2} # straight 3-byte
-
| \xEF[\x80-\xBE]{2} #
-
| \xEF\xBF[\x80-\xBD] # excluding U+fffe and U+ffff
-
| \xED[\x80-\x9F][\x80-\xBF] # excluding surrogates
-
| \xF0[\x90-\xBF][\x80-\xBF]{2} # planes 1-3
-
| [\xF1-\xF3][\x80-\xBF]{3} # planes 4-15
-
| \xF4[\x80-\x8F][\x80-\xBF]{2} # plane 16
-
)*$/nx;
-
end
-
-
# Constructor
-
# +arg+ if a String, the content is set to the String. If a Text,
-
# the object is shallowly cloned.
-
#
-
# +respect_whitespace+ (boolean, false) if true, whitespace is
-
# respected
-
#
-
# +parent+ (nil) if this is a Parent object, the parent
-
# will be set to this.
-
#
-
# +raw+ (nil) This argument can be given three values.
-
# If true, then the value of used to construct this object is expected to
-
# contain no unescaped XML markup, and REXML will not change the text. If
-
# this value is false, the string may contain any characters, and REXML will
-
# escape any and all defined entities whose values are contained in the
-
# text. If this value is nil (the default), then the raw value of the
-
# parent will be used as the raw value for this node. If there is no raw
-
# value for the parent, and no value is supplied, the default is false.
-
# Use this field if you have entities defined for some text, and you don't
-
# want REXML to escape that text in output.
-
# Text.new( "<&", false, nil, false ) #-> "<&"
-
# Text.new( "<&", false, nil, false ) #-> "&lt;&amp;"
-
# Text.new( "<&", false, nil, true ) #-> Parse exception
-
# Text.new( "<&", false, nil, true ) #-> "<&"
-
# # Assume that the entity "s" is defined to be "sean"
-
# # and that the entity "r" is defined to be "russell"
-
# Text.new( "sean russell" ) #-> "&s; &r;"
-
# Text.new( "sean russell", false, nil, true ) #-> "sean russell"
-
#
-
# +entity_filter+ (nil) This can be an array of entities to match in the
-
# supplied text. This argument is only useful if +raw+ is set to false.
-
# Text.new( "sean russell", false, nil, false, ["s"] ) #-> "&s; russell"
-
# Text.new( "sean russell", false, nil, true, ["s"] ) #-> "sean russell"
-
# In the last example, the +entity_filter+ argument is ignored.
-
#
-
# +illegal+ INTERNAL USE ONLY
-
1
def initialize(arg, respect_whitespace=false, parent=nil, raw=nil,
-
entity_filter=nil, illegal=NEEDS_A_SECOND_CHECK )
-
-
374
@raw = false
-
374
@parent = nil
-
-
374
if parent
-
super( parent )
-
@raw = parent.raw
-
end
-
-
374
@raw = raw unless raw.nil?
-
374
@entity_filter = entity_filter
-
374
@normalized = @unnormalized = nil
-
-
374
if arg.kind_of? String
-
374
@string = arg.dup
-
374
@string.squeeze!(" \n\t") unless respect_whitespace
-
elsif arg.kind_of? Text
-
@string = arg.to_s
-
@raw = arg.raw
-
elsif
-
raise "Illegal argument of type #{arg.type} for Text constructor (#{arg})"
-
end
-
-
374
@string.gsub!( /\r\n?/, "\n" )
-
-
374
Text.check(@string, illegal, doctype) if @raw
-
end
-
-
1
def parent= parent
-
374
super(parent)
-
374
Text.check(@string, NEEDS_A_SECOND_CHECK, doctype) if @raw and @parent
-
end
-
-
# check for illegal characters
-
1
def Text.check string, pattern, doctype
-
-
# illegal anywhere
-
911
if string !~ VALID_XML_CHARS
-
if String.method_defined? :encode
-
string.chars.each do |c|
-
case c.ord
-
when *VALID_CHAR
-
else
-
raise "Illegal character #{c.inspect} in raw string \"#{string}\""
-
end
-
end
-
else
-
string.scan(/[\x00-\x7F]|[\x80-\xBF][\xC0-\xF0]*|[\xC0-\xF0]/n) do |c|
-
case c.unpack('U')
-
when *VALID_CHAR
-
else
-
raise "Illegal character #{c.inspect} in raw string \"#{string}\""
-
end
-
end
-
end
-
end
-
-
# context sensitive
-
911
string.scan(pattern) do
-
8
if $1[-1] != ?;
-
raise "Illegal character '#{$1}' in raw string \"#{string}\""
-
elsif $1[0] == ?&
-
8
if $5 and $5[0] == ?#
-
case ($5[1] == ?x ? $5[2..-1].to_i(16) : $5[1..-1].to_i)
-
when *VALID_CHAR
-
else
-
raise "Illegal character '#{$1}' in raw string \"#{string}\""
-
end
-
# FIXME: below can't work but this needs API change.
-
# elsif @parent and $3 and !SUBSTITUTES.include?($1)
-
# if !doctype or !doctype.entities.has_key?($3)
-
# raise "Undeclared entity '#{$1}' in raw string \"#{string}\""
-
# end
-
end
-
end
-
end
-
end
-
-
1
def node_type
-
1341
:text
-
end
-
-
1
def empty?
-
@string.size==0
-
end
-
-
-
1
def clone
-
return Text.new(self)
-
end
-
-
-
# Appends text to this text node. The text is appended in the +raw+ mode
-
# of this text node.
-
1
def <<( to_append )
-
@string << to_append.gsub( /\r\n?/, "\n" )
-
end
-
-
-
# +other+ a String or a Text
-
# +returns+ the result of (to_s <=> arg.to_s)
-
1
def <=>( other )
-
to_s() <=> other.to_s
-
end
-
-
1
def doctype
-
903
if @parent
-
529
doc = @parent.document
-
529
doc.doctype if doc
-
end
-
end
-
-
1
REFERENCE = /#{Entity::REFERENCE}/
-
# Returns the string value of this text node. This string is always
-
# escaped, meaning that it is a valid XML text node string, and all
-
# entities that can be escaped, have been inserted. This method respects
-
# the entity filter set in the constructor.
-
#
-
# # Assume that the entity "s" is defined to be "sean", and that the
-
# # entity "r" is defined to be "russell"
-
# t = Text.new( "< & sean russell", false, nil, false, ['s'] )
-
# t.to_s #-> "< & &s; russell"
-
# t = Text.new( "< & &s; russell", false, nil, false )
-
# t.to_s #-> "< & &s; russell"
-
# u = Text.new( "sean russell", false, nil, true )
-
# u.to_s #-> "sean russell"
-
1
def to_s
-
201
return @string if @raw
-
return @normalized if @normalized
-
-
@normalized = Text::normalize( @string, doctype, @entity_filter )
-
end
-
-
1
def inspect
-
@string.inspect
-
end
-
-
# Returns the string value of this text. This is the text without
-
# entities, as it might be used programmatically, or printed to the
-
# console. This ignores the 'raw' attribute setting, and any
-
# entity_filter.
-
#
-
# # Assume that the entity "s" is defined to be "sean", and that the
-
# # entity "r" is defined to be "russell"
-
# t = Text.new( "< & sean russell", false, nil, false, ['s'] )
-
# t.value #-> "< & sean russell"
-
# t = Text.new( "< & &s; russell", false, nil, false )
-
# t.value #-> "< & sean russell"
-
# u = Text.new( "sean russell", false, nil, true )
-
# u.value #-> "sean russell"
-
1
def value
-
300
return @unnormalized if @unnormalized
-
155
@unnormalized = Text::unnormalize( @string, doctype )
-
end
-
-
# Sets the contents of this text node. This expects the text to be
-
# unnormalized. It returns self.
-
#
-
# e = Element.new( "a" )
-
# e.add_text( "foo" ) # <a>foo</a>
-
# e[0].value = "bar" # <a>bar</a>
-
# e[0].value = "<a>" # <a><a></a>
-
1
def value=( val )
-
@string = val.gsub( /\r\n?/, "\n" )
-
@unnormalized = nil
-
@normalized = nil
-
@raw = false
-
end
-
-
1
def wrap(string, width, addnewline=false)
-
# Recursively wrap string at width.
-
return string if string.length <= width
-
place = string.rindex(' ', width) # Position in string with last ' ' before cutoff
-
if addnewline then
-
return "\n" + string[0,place] + "\n" + wrap(string[place+1..-1], width)
-
else
-
return string[0,place] + "\n" + wrap(string[place+1..-1], width)
-
end
-
end
-
-
1
def indent_text(string, level=1, style="\t", indentfirstline=true)
-
return string if level < 0
-
new_string = ''
-
string.each_line { |line|
-
indent_string = style * level
-
new_line = (indent_string + line).sub(/[\s]+$/,'')
-
new_string << new_line
-
}
-
new_string.strip! unless indentfirstline
-
return new_string
-
end
-
-
# == DEPRECATED
-
# See REXML::Formatters
-
#
-
1
def write( writer, indent=-1, transitive=false, ie_hack=false )
-
Kernel.warn("#{self.class.name}.write is deprecated. See REXML::Formatters")
-
formatter = if indent > -1
-
REXML::Formatters::Pretty.new( indent )
-
else
-
REXML::Formatters::Default.new
-
end
-
formatter.write( self, writer )
-
end
-
-
# FIXME
-
# This probably won't work properly
-
1
def xpath
-
path = @parent.xpath
-
path += "/text()"
-
return path
-
end
-
-
# Writes out text, substituting special characters beforehand.
-
# +out+ A String, IO, or any other object supporting <<( String )
-
# +input+ the text to substitute and the write out
-
#
-
# z=utf8.unpack("U*")
-
# ascOut=""
-
# z.each{|r|
-
# if r < 0x100
-
# ascOut.concat(r.chr)
-
# else
-
# ascOut.concat(sprintf("&#x%x;", r))
-
# end
-
# }
-
# puts ascOut
-
1
def write_with_substitution out, input
-
copy = input.clone
-
# Doing it like this rather than in a loop improves the speed
-
copy.gsub!( SPECIALS[0], SUBSTITUTES[0] )
-
copy.gsub!( SPECIALS[1], SUBSTITUTES[1] )
-
copy.gsub!( SPECIALS[2], SUBSTITUTES[2] )
-
copy.gsub!( SPECIALS[3], SUBSTITUTES[3] )
-
copy.gsub!( SPECIALS[4], SUBSTITUTES[4] )
-
copy.gsub!( SPECIALS[5], SUBSTITUTES[5] )
-
out << copy
-
end
-
-
# Reads text, substituting entities
-
1
def Text::read_with_substitution( input, illegal=nil )
-
copy = input.clone
-
-
if copy =~ illegal
-
raise ParseException.new( "malformed text: Illegal character #$& in \"#{copy}\"" )
-
end if illegal
-
-
copy.gsub!( /\r\n?/, "\n" )
-
if copy.include? ?&
-
copy.gsub!( SETUTITSBUS[0], SLAICEPS[0] )
-
copy.gsub!( SETUTITSBUS[1], SLAICEPS[1] )
-
copy.gsub!( SETUTITSBUS[2], SLAICEPS[2] )
-
copy.gsub!( SETUTITSBUS[3], SLAICEPS[3] )
-
copy.gsub!( SETUTITSBUS[4], SLAICEPS[4] )
-
copy.gsub!( /�*((?:\d+)|(?:x[a-f0-9]+));/ ) {
-
m=$1
-
#m='0' if m==''
-
m = "0#{m}" if m[0] == ?x
-
[Integer(m)].pack('U*')
-
}
-
end
-
copy
-
end
-
-
1
EREFERENCE = /&(?!#{Entity::NAME};)/
-
# Escapes all possible entities
-
1
def Text::normalize( input, doctype=nil, entity_filter=nil )
-
copy = input.to_s
-
# Doing it like this rather than in a loop improves the speed
-
#copy = copy.gsub( EREFERENCE, '&' )
-
copy = copy.gsub( "&", "&" )
-
if doctype
-
# Replace all ampersands that aren't part of an entity
-
doctype.entities.each_value do |entity|
-
copy = copy.gsub( entity.value,
-
"&#{entity.name};" ) if entity.value and
-
not( entity_filter and entity_filter.include?(entity) )
-
end
-
else
-
# Replace all ampersands that aren't part of an entity
-
DocType::DEFAULT_ENTITIES.each_value do |entity|
-
copy = copy.gsub(entity.value, "&#{entity.name};" )
-
end
-
end
-
copy
-
end
-
-
# Unescapes all possible entities
-
1
def Text::unnormalize( string, doctype=nil, filter=nil, illegal=nil )
-
313
string.gsub( /\r\n?/, "\n" ).gsub( REFERENCE ) {
-
4
ref = $&
-
4
if ref[1] == ?#
-
if ref[2] == ?x
-
[ref[3...-1].to_i(16)].pack('U*')
-
else
-
[ref[2...-1].to_i].pack('U*')
-
end
-
elsif ref == '&'
-
'&'
-
elsif filter and filter.include?( ref[1...-1] )
-
ref
-
elsif doctype
-
doctype.entity( ref[1...-1] ) or ref
-
else
-
4
entity_value = DocType::DEFAULT_ENTITIES[ ref[1...-1] ]
-
4
entity_value ? entity_value.value : ref
-
end
-
}
-
end
-
end
-
end
-
1
require 'rexml/parseexception'
-
1
module REXML
-
1
class UndefinedNamespaceException < ParseException
-
1
def initialize( prefix, source, parser )
-
super( "Undefined prefix #{prefix} found" )
-
end
-
end
-
end
-
1
module REXML
-
1
module Validation
-
1
class ValidationException < RuntimeError
-
1
def initialize msg
-
super
-
end
-
end
-
end
-
end
-
1
require 'rexml/encoding'
-
1
require 'rexml/source'
-
-
1
module REXML
-
# NEEDS DOCUMENTATION
-
1
class XMLDecl < Child
-
1
include Encoding
-
-
1
DEFAULT_VERSION = "1.0";
-
1
DEFAULT_ENCODING = "UTF-8";
-
1
DEFAULT_STANDALONE = "no";
-
1
START = '<\?xml';
-
1
STOP = '\?>';
-
-
1
attr_accessor :version, :standalone
-
1
attr_reader :writeencoding, :writethis
-
-
1
def initialize(version=DEFAULT_VERSION, encoding=nil, standalone=nil)
-
10
@writethis = true
-
10
@writeencoding = !encoding.nil?
-
10
if version.kind_of? XMLDecl
-
super()
-
@version = version.version
-
self.encoding = version.encoding
-
@writeencoding = version.writeencoding
-
@standalone = version.standalone
-
else
-
10
super()
-
10
@version = version
-
10
self.encoding = encoding
-
10
@standalone = standalone
-
end
-
10
@version = DEFAULT_VERSION if @version.nil?
-
end
-
-
1
def clone
-
XMLDecl.new(self)
-
end
-
-
# indent::
-
# Ignored. There must be no whitespace before an XML declaration
-
# transitive::
-
# Ignored
-
# ie_hack::
-
# Ignored
-
1
def write(writer, indent=-1, transitive=false, ie_hack=false)
-
return nil unless @writethis or writer.kind_of? Output
-
writer << START.sub(/\\/u, '')
-
if writer.kind_of? Output
-
writer << " #{content writer.encoding}"
-
else
-
writer << " #{content encoding}"
-
end
-
writer << STOP.sub(/\\/u, '')
-
end
-
-
1
def ==( other )
-
other.kind_of?(XMLDecl) and
-
other.version == @version and
-
other.encoding == self.encoding and
-
other.standalone == @standalone
-
end
-
-
1
def xmldecl version, encoding, standalone
-
@version = version
-
self.encoding = encoding
-
@standalone = standalone
-
end
-
-
1
def node_type
-
95
:xmldecl
-
end
-
-
1
alias :stand_alone? :standalone
-
1
alias :old_enc= :encoding=
-
-
1
def encoding=( enc )
-
10
if enc.nil?
-
1
self.old_enc = "UTF-8"
-
1
@writeencoding = false
-
else
-
9
self.old_enc = enc
-
9
@writeencoding = true
-
end
-
10
self.dowrite
-
end
-
-
# Only use this if you do not want the XML declaration to be written;
-
# this object is ignored by the XML writer. Otherwise, instantiate your
-
# own XMLDecl and add it to the document.
-
#
-
# Note that XML 1.1 documents *must* include an XML declaration
-
1
def XMLDecl.default
-
1
rv = XMLDecl.new( "1.0" )
-
1
rv.nowrite
-
1
rv
-
end
-
-
1
def nowrite
-
1
@writethis = false
-
end
-
-
1
def dowrite
-
10
@writethis = true
-
end
-
-
1
def inspect
-
START.sub(/\\/u, '') + " ... " + STOP.sub(/\\/u, '')
-
end
-
-
1
private
-
1
def content(enc)
-
rv = "version='#@version'"
-
rv << " encoding='#{enc}'" if @writeencoding || enc !~ /utf-8/i
-
rv << " standalone='#@standalone'" if @standalone
-
rv
-
end
-
end
-
end
-
1
module REXML
-
# Defines a number of tokens used for parsing XML. Not for general
-
# consumption.
-
1
module XMLTokens
-
1
NCNAME_STR= '[\w:][\-\w.]*'
-
1
NAME_STR= "(?:#{NCNAME_STR}:)?#{NCNAME_STR}"
-
-
1
NAMECHAR = '[\-\w\.:]'
-
1
NAME = "([\\w:]#{NAMECHAR}*)"
-
1
NMTOKEN = "(?:#{NAMECHAR})+"
-
1
NMTOKENS = "#{NMTOKEN}(\\s+#{NMTOKEN})*"
-
1
REFERENCE = "(?:&#{NAME};|&#\\d+;|&#x[0-9a-fA-F]+;)"
-
-
#REFERENCE = "(?:#{ENTITYREF}|#{CHARREF})"
-
#ENTITYREF = "&#{NAME};"
-
#CHARREF = "&#\\d+;|&#x[0-9a-fA-F]+;"
-
end
-
end
-
1
require 'rexml/functions'
-
1
require 'rexml/xpath_parser'
-
-
1
module REXML
-
# Wrapper class. Use this class to access the XPath functions.
-
1
class XPath
-
1
include Functions
-
# A base Hash object, supposing to be used when initializing a
-
# default empty namespaces set, but is currently unused.
-
# TODO: either set the namespaces=EMPTY_HASH, or deprecate this.
-
1
EMPTY_HASH = {}
-
-
# Finds and returns the first node that matches the supplied xpath.
-
# element::
-
# The context element
-
# path::
-
# The xpath to search for. If not supplied or nil, returns the first
-
# node matching '*'.
-
# namespaces::
-
# If supplied, a Hash which defines a namespace mapping.
-
# variables::
-
# If supplied, a Hash which maps $variables in the query
-
# to values. This can be used to avoid XPath injection attacks
-
# or to automatically handle escaping string values.
-
#
-
# XPath.first( node )
-
# XPath.first( doc, "//b"} )
-
# XPath.first( node, "a/x:b", { "x"=>"http://doofus" } )
-
# XPath.first( node, '/book/publisher/text()=$publisher', {}, {"publisher"=>"O'Reilly"})
-
1
def XPath::first element, path=nil, namespaces=nil, variables={}
-
19
raise "The namespaces argument, if supplied, must be a hash object." unless namespaces.nil? or namespaces.kind_of?(Hash)
-
19
raise "The variables argument, if supplied, must be a hash object." unless variables.kind_of?(Hash)
-
19
parser = XPathParser.new
-
19
parser.namespaces = namespaces
-
19
parser.variables = variables
-
19
path = "*" unless path
-
19
element = [element] unless element.kind_of? Array
-
19
parser.parse(path, element).flatten[0]
-
end
-
-
# Iterates over nodes that match the given path, calling the supplied
-
# block with the match.
-
# element::
-
# The context element
-
# path::
-
# The xpath to search for. If not supplied or nil, defaults to '*'
-
# namespaces::
-
# If supplied, a Hash which defines a namespace mapping
-
# variables::
-
# If supplied, a Hash which maps $variables in the query
-
# to values. This can be used to avoid XPath injection attacks
-
# or to automatically handle escaping string values.
-
#
-
# XPath.each( node ) { |el| ... }
-
# XPath.each( node, '/*[@attr='v']' ) { |el| ... }
-
# XPath.each( node, 'ancestor::x' ) { |el| ... }
-
# XPath.each( node, '/book/publisher/text()=$publisher', {}, {"publisher"=>"O'Reilly"}) \
-
# {|el| ... }
-
1
def XPath::each element, path=nil, namespaces=nil, variables={}, &block
-
25
raise "The namespaces argument, if supplied, must be a hash object." unless namespaces.nil? or namespaces.kind_of?(Hash)
-
25
raise "The variables argument, if supplied, must be a hash object." unless variables.kind_of?(Hash)
-
25
parser = XPathParser.new
-
25
parser.namespaces = namespaces
-
25
parser.variables = variables
-
25
path = "*" unless path
-
25
element = [element] unless element.kind_of? Array
-
25
parser.parse(path, element).each( &block )
-
end
-
-
# Returns an array of nodes matching a given XPath.
-
1
def XPath::match element, path=nil, namespaces=nil, variables={}
-
parser = XPathParser.new
-
parser.namespaces = namespaces
-
parser.variables = variables
-
path = "*" unless path
-
element = [element] unless element.kind_of? Array
-
parser.parse(path,element)
-
end
-
end
-
end
-
1
require 'rexml/namespace'
-
1
require 'rexml/xmltokens'
-
1
require 'rexml/attribute'
-
1
require 'rexml/syncenumerator'
-
1
require 'rexml/parsers/xpathparser'
-
-
1
class Object
-
# provides a unified +clone+ operation, for REXML::XPathParser
-
# to use across multiple Object types
-
1
def dclone
-
1178
clone
-
end
-
end
-
1
class Symbol
-
# provides a unified +clone+ operation, for REXML::XPathParser
-
# to use across multiple Object types
-
1768
def dclone ; self ; end
-
end
-
1
class Fixnum
-
# provides a unified +clone+ operation, for REXML::XPathParser
-
# to use across multiple Object types
-
1
def dclone ; self ; end
-
end
-
1
class Float
-
# provides a unified +clone+ operation, for REXML::XPathParser
-
# to use across multiple Object types
-
1
def dclone ; self ; end
-
end
-
1
class Array
-
# provides a unified +clone+ operation, for REXML::XPathParser
-
# to use across multiple Object+ types
-
1
def dclone
-
589
klone = self.clone
-
589
klone.clear
-
3534
self.each{|v| klone << v.dclone}
-
589
klone
-
end
-
end
-
-
1
module REXML
-
# You don't want to use this class. Really. Use XPath, which is a wrapper
-
# for this class. Believe me. You don't want to poke around in here.
-
# There is strange, dark magic at work in this code. Beware. Go back! Go
-
# back while you still can!
-
1
class XPathParser
-
1
include XMLTokens
-
1
LITERAL = /^'([^']*)'|^"([^"]*)"/u
-
-
1
def initialize( )
-
44
@parser = REXML::Parsers::XPathParser.new
-
44
@namespaces = nil
-
44
@variables = {}
-
end
-
-
1
def namespaces=( namespaces={} )
-
44
Functions::namespace_context = namespaces
-
44
@namespaces = namespaces
-
end
-
-
1
def variables=( vars={} )
-
44
Functions::variables = vars
-
44
@variables = vars
-
end
-
-
1
def parse path, nodeset
-
#puts "#"*40
-
44
path_stack = @parser.parse( path )
-
#puts "PARSE: #{path} => #{path_stack.inspect}"
-
#puts "PARSE: nodeset = #{nodeset.inspect}"
-
44
match( path_stack, nodeset )
-
end
-
-
1
def get_first path, nodeset
-
#puts "#"*40
-
path_stack = @parser.parse( path )
-
#puts "PARSE: #{path} => #{path_stack.inspect}"
-
#puts "PARSE: nodeset = #{nodeset.inspect}"
-
first( path_stack, nodeset )
-
end
-
-
1
def predicate path, nodeset
-
path_stack = @parser.parse( path )
-
expr( path_stack, nodeset )
-
end
-
-
1
def []=( variable_name, value )
-
@variables[ variable_name ] = value
-
end
-
-
-
# Performs a depth-first (document order) XPath search, and returns the
-
# first match. This is the fastest, lightest way to return a single result.
-
#
-
# FIXME: This method is incomplete!
-
1
def first( path_stack, node )
-
#puts "#{depth}) Entering match( #{path.inspect}, #{tree.inspect} )"
-
return nil if path.size == 0
-
-
case path[0]
-
when :document
-
# do nothing
-
return first( path[1..-1], node )
-
when :child
-
for c in node.children
-
#puts "#{depth}) CHILD checking #{name(c)}"
-
r = first( path[1..-1], c )
-
#puts "#{depth}) RETURNING #{r.inspect}" if r
-
return r if r
-
end
-
when :qname
-
name = path[2]
-
#puts "#{depth}) QNAME #{name(tree)} == #{name} (path => #{path.size})"
-
if node.name == name
-
#puts "#{depth}) RETURNING #{tree.inspect}" if path.size == 3
-
return node if path.size == 3
-
return first( path[3..-1], node )
-
else
-
return nil
-
end
-
when :descendant_or_self
-
r = first( path[1..-1], node )
-
return r if r
-
for c in node.children
-
r = first( path, c )
-
return r if r
-
end
-
when :node
-
return first( path[1..-1], node )
-
when :any
-
return first( path[1..-1], node )
-
end
-
return nil
-
end
-
-
-
1
def match( path_stack, nodeset )
-
#puts "MATCH: path_stack = #{path_stack.inspect}"
-
#puts "MATCH: nodeset = #{nodeset.inspect}"
-
44
r = expr( path_stack, nodeset )
-
#puts "MAIN EXPR => #{r.inspect}"
-
44
r
-
end
-
-
1
private
-
-
-
# Returns a String namespace for a node, given a prefix
-
# The rules are:
-
#
-
# 1. Use the supplied namespace mapping first.
-
# 2. If no mapping was supplied, use the context node to look up the namespace
-
1
def get_namespace( node, prefix )
-
570
if @namespaces
-
return @namespaces[prefix] || ''
-
else
-
570
return node.namespace( prefix ) if node.node_type == :element
-
247
return ''
-
end
-
end
-
-
-
# Expr takes a stack of path elements and a set of nodes (either a Parent
-
# or an Array and returns an Array of matching nodes
-
1
ALL = [ :attribute, :element, :text, :processing_instruction, :comment ]
-
1
ELEMENTS = [ :element ]
-
1
def expr( path_stack, nodeset, context=nil )
-
#puts "#"*15
-
#puts "In expr with #{path_stack.inspect}"
-
#puts "Returning" if path_stack.length == 0 || nodeset.length == 0
-
633
node_types = ELEMENTS
-
633
return nodeset if path_stack.length == 0 || nodeset.length == 0
-
633
while path_stack.length > 0
-
#puts "#"*5
-
#puts "Path stack = #{path_stack.inspect}"
-
#puts "Nodeset is #{nodeset.inspect}"
-
1855
if nodeset.length == 0
-
323
path_stack.clear
-
323
return []
-
end
-
1532
case (op = path_stack.shift)
-
when :document
-
19
nodeset = [ nodeset[0].root_node ]
-
#puts ":document, nodeset = #{nodeset.inspect}"
-
-
when :qname
-
#puts "IN QNAME"
-
266
prefix = path_stack.shift
-
266
name = path_stack.shift
-
266
nodeset.delete_if do |node|
-
# FIXME: This DOUBLES the time XPath searches take
-
570
ns = get_namespace( node, prefix )
-
#puts "NS = #{ns.inspect}"
-
#puts "node.node_type == :element => #{node.node_type == :element}"
-
570
if node.node_type == :element
-
#puts "node.name == #{name} => #{node.name == name}"
-
323
if node.name == name
-
#puts "node.namespace == #{ns.inspect} => #{node.namespace == ns}"
-
end
-
end
-
!(node.node_type == :element and
-
570
node.name == name and
-
570
node.namespace == ns )
-
end
-
266
node_types = ELEMENTS
-
-
when :any
-
#puts "ANY 1: nodeset = #{nodeset.inspect}"
-
#puts "ANY 1: node_types = #{node_types.inspect}"
-
402
nodeset.delete_if { |node| !node_types.include?(node.node_type) }
-
#puts "ANY 2: nodeset = #{nodeset.inspect}"
-
-
when :self
-
# This space left intentionally blank
-
-
when :processing_instruction
-
target = path_stack.shift
-
nodeset.delete_if do |node|
-
(node.node_type != :processing_instruction) or
-
( target!='' and ( node.target != target ) )
-
end
-
-
when :text
-
nodeset.delete_if { |node| node.node_type != :text }
-
-
when :comment
-
nodeset.delete_if { |node| node.node_type != :comment }
-
-
when :node
-
# This space left intentionally blank
-
589
node_types = ALL
-
-
when :child
-
614
new_nodeset = []
-
614
nt = nil
-
614
nodeset.each do |node|
-
614
nt = node.node_type
-
614
new_nodeset += node.children if nt == :element or nt == :document
-
end
-
614
nodeset = new_nodeset
-
614
node_types = ELEMENTS
-
-
when :literal
-
return path_stack.shift
-
-
when :attribute
-
new_nodeset = []
-
case path_stack.shift
-
when :qname
-
prefix = path_stack.shift
-
name = path_stack.shift
-
for element in nodeset
-
if element.node_type == :element
-
#puts "Element name = #{element.name}"
-
#puts "get_namespace( #{element.inspect}, #{prefix} ) = #{get_namespace(element, prefix)}"
-
attrib = element.attribute( name, get_namespace(element, prefix) )
-
#puts "attrib = #{attrib.inspect}"
-
new_nodeset << attrib if attrib
-
end
-
end
-
when :any
-
#puts "ANY"
-
for element in nodeset
-
if element.node_type == :element
-
new_nodeset += element.attributes.to_a
-
end
-
end
-
end
-
nodeset = new_nodeset
-
-
when :parent
-
#puts "PARENT 1: nodeset = #{nodeset}"
-
nodeset = nodeset.collect{|n| n.parent}.compact
-
#nodeset = expr(path_stack.dclone, nodeset.collect{|n| n.parent}.compact)
-
#puts "PARENT 2: nodeset = #{nodeset.inspect}"
-
node_types = ELEMENTS
-
-
when :ancestor
-
new_nodeset = []
-
nodeset.each do |node|
-
while node.parent
-
node = node.parent
-
new_nodeset << node unless new_nodeset.include? node
-
end
-
end
-
nodeset = new_nodeset
-
node_types = ELEMENTS
-
-
when :ancestor_or_self
-
new_nodeset = []
-
nodeset.each do |node|
-
if node.node_type == :element
-
new_nodeset << node
-
while ( node.parent )
-
node = node.parent
-
new_nodeset << node unless new_nodeset.include? node
-
end
-
end
-
end
-
nodeset = new_nodeset
-
node_types = ELEMENTS
-
-
when :predicate
-
new_nodeset = []
-
subcontext = { :size => nodeset.size }
-
pred = path_stack.shift
-
nodeset.each_with_index { |node, index|
-
subcontext[ :node ] = node
-
#puts "PREDICATE SETTING CONTEXT INDEX TO #{index+1}"
-
subcontext[ :index ] = index+1
-
pc = pred.dclone
-
#puts "#{node.hash}) Recursing with #{pred.inspect} and [#{node.inspect}]"
-
result = expr( pc, [node], subcontext )
-
result = result[0] if result.kind_of? Array and result.length == 1
-
#puts "#{node.hash}) Result = #{result.inspect} (#{result.class.name})"
-
if result.kind_of? Numeric
-
#puts "Adding node #{node.inspect}" if result == (index+1)
-
new_nodeset << node if result == (index+1)
-
elsif result.instance_of? Array
-
if result.size > 0 and result.inject(false) {|k,s| s or k}
-
#puts "Adding node #{node.inspect}" if result.size > 0
-
new_nodeset << node if result.size > 0
-
end
-
else
-
#puts "Adding node #{node.inspect}" if result
-
new_nodeset << node if result
-
end
-
}
-
#puts "New nodeset = #{new_nodeset.inspect}"
-
#puts "Path_stack = #{path_stack.inspect}"
-
nodeset = new_nodeset
-
=begin
-
predicate = path_stack.shift
-
ns = nodeset.clone
-
result = expr( predicate, ns )
-
#puts "Result = #{result.inspect} (#{result.class.name})"
-
#puts "nodeset = #{nodeset.inspect}"
-
if result.kind_of? Array
-
nodeset = result.zip(ns).collect{|m,n| n if m}.compact
-
else
-
nodeset = result ? nodeset : []
-
end
-
#puts "Outgoing NS = #{nodeset.inspect}"
-
=end
-
-
when :descendant_or_self
-
19
rv = descendant_or_self( path_stack, nodeset )
-
19
path_stack.clear
-
19
nodeset = rv
-
19
node_types = ELEMENTS
-
-
when :descendant
-
results = []
-
nt = nil
-
nodeset.each do |node|
-
nt = node.node_type
-
results += expr( path_stack.dclone.unshift( :descendant_or_self ),
-
node.children ) if nt == :element or nt == :document
-
end
-
nodeset = results
-
node_types = ELEMENTS
-
-
when :following_sibling
-
#puts "FOLLOWING_SIBLING 1: nodeset = #{nodeset}"
-
results = []
-
nodeset.each do |node|
-
next if node.parent.nil?
-
all_siblings = node.parent.children
-
current_index = all_siblings.index( node )
-
following_siblings = all_siblings[ current_index+1 .. -1 ]
-
results += expr( path_stack.dclone, following_siblings )
-
end
-
#puts "FOLLOWING_SIBLING 2: nodeset = #{nodeset}"
-
nodeset = results
-
-
when :preceding_sibling
-
results = []
-
nodeset.each do |node|
-
next if node.parent.nil?
-
all_siblings = node.parent.children
-
current_index = all_siblings.index( node )
-
preceding_siblings = all_siblings[ 0, current_index ].reverse
-
results += preceding_siblings
-
end
-
nodeset = results
-
node_types = ELEMENTS
-
-
when :preceding
-
new_nodeset = []
-
nodeset.each do |node|
-
new_nodeset += preceding( node )
-
end
-
#puts "NEW NODESET => #{new_nodeset.inspect}"
-
nodeset = new_nodeset
-
node_types = ELEMENTS
-
-
when :following
-
new_nodeset = []
-
nodeset.each do |node|
-
new_nodeset += following( node )
-
end
-
nodeset = new_nodeset
-
node_types = ELEMENTS
-
-
when :namespace
-
#puts "In :namespace"
-
new_nodeset = []
-
prefix = path_stack.shift
-
nodeset.each do |node|
-
if (node.node_type == :element or node.node_type == :attribute)
-
if @namespaces
-
namespaces = @namespaces
-
elsif (node.node_type == :element)
-
namespaces = node.namespaces
-
else
-
namespaces = node.element.namesapces
-
end
-
#puts "Namespaces = #{namespaces.inspect}"
-
#puts "Prefix = #{prefix.inspect}"
-
#puts "Node.namespace = #{node.namespace}"
-
if (node.namespace == namespaces[prefix])
-
new_nodeset << node
-
end
-
end
-
end
-
nodeset = new_nodeset
-
-
when :variable
-
var_name = path_stack.shift
-
return @variables[ var_name ]
-
-
# :and, :or, :eq, :neq, :lt, :lteq, :gt, :gteq
-
# TODO: Special case for :or and :and -- not evaluate the right
-
# operand if the left alone determines result (i.e. is true for
-
# :or and false for :and).
-
when :eq, :neq, :lt, :lteq, :gt, :gteq, :or
-
left = expr( path_stack.shift, nodeset.dup, context )
-
#puts "LEFT => #{left.inspect} (#{left.class.name})"
-
right = expr( path_stack.shift, nodeset.dup, context )
-
#puts "RIGHT => #{right.inspect} (#{right.class.name})"
-
res = equality_relational_compare( left, op, right )
-
#puts "RES => #{res.inspect}"
-
return res
-
-
when :and
-
left = expr( path_stack.shift, nodeset.dup, context )
-
#puts "LEFT => #{left.inspect} (#{left.class.name})"
-
return [] unless left
-
if left.respond_to?(:inject) and !left.inject(false) {|a,b| a | b}
-
return []
-
end
-
right = expr( path_stack.shift, nodeset.dup, context )
-
#puts "RIGHT => #{right.inspect} (#{right.class.name})"
-
res = equality_relational_compare( left, op, right )
-
#puts "RES => #{res.inspect}"
-
return res
-
-
when :div
-
left = Functions::number(expr(path_stack.shift, nodeset, context)).to_f
-
right = Functions::number(expr(path_stack.shift, nodeset, context)).to_f
-
return (left / right)
-
-
when :mod
-
left = Functions::number(expr(path_stack.shift, nodeset, context )).to_f
-
right = Functions::number(expr(path_stack.shift, nodeset, context )).to_f
-
return (left % right)
-
-
when :mult
-
left = Functions::number(expr(path_stack.shift, nodeset, context )).to_f
-
right = Functions::number(expr(path_stack.shift, nodeset, context )).to_f
-
return (left * right)
-
-
when :plus
-
left = Functions::number(expr(path_stack.shift, nodeset, context )).to_f
-
right = Functions::number(expr(path_stack.shift, nodeset, context )).to_f
-
return (left + right)
-
-
when :minus
-
left = Functions::number(expr(path_stack.shift, nodeset, context )).to_f
-
right = Functions::number(expr(path_stack.shift, nodeset, context )).to_f
-
return (left - right)
-
-
when :union
-
left = expr( path_stack.shift, nodeset, context )
-
right = expr( path_stack.shift, nodeset, context )
-
return (left | right)
-
-
when :neg
-
res = expr( path_stack, nodeset, context )
-
return -(res.to_f)
-
-
when :not
-
when :function
-
func_name = path_stack.shift.tr('-','_')
-
arguments = path_stack.shift
-
#puts "FUNCTION 0: #{func_name}(#{arguments.collect{|a|a.inspect}.join(', ')})"
-
subcontext = context ? nil : { :size => nodeset.size }
-
-
res = []
-
cont = context
-
nodeset.each_with_index { |n, i|
-
if subcontext
-
subcontext[:node] = n
-
subcontext[:index] = i
-
cont = subcontext
-
end
-
arg_clone = arguments.dclone
-
args = arg_clone.collect { |arg|
-
#puts "FUNCTION 1: Calling expr( #{arg.inspect}, [#{n.inspect}] )"
-
expr( arg, [n], cont )
-
}
-
#puts "FUNCTION 2: #{func_name}(#{args.collect{|a|a.inspect}.join(', ')})"
-
Functions.context = cont
-
res << Functions.send( func_name, *args )
-
#puts "FUNCTION 3: #{res[-1].inspect}"
-
}
-
return res
-
-
end
-
end # while
-
#puts "EXPR returning #{nodeset.inspect}"
-
310
return nodeset
-
end
-
-
-
##########################################################
-
# FIXME
-
# The next two methods are BAD MOJO!
-
# This is my achilles heel. If anybody thinks of a better
-
# way of doing this, be my guest. This really sucks, but
-
# it is a wonder it works at all.
-
# ########################################################
-
-
1
def descendant_or_self( path_stack, nodeset )
-
19
rs = []
-
#puts "#"*80
-
#puts "PATH_STACK = #{path_stack.inspect}"
-
#puts "NODESET = #{nodeset.collect{|n|n.inspect}.inspect}"
-
19
d_o_s( path_stack, nodeset, rs )
-
#puts "RS = #{rs.collect{|n|n.inspect}.inspect}"
-
19
document_order(rs.flatten.compact)
-
#rs.flatten.compact
-
end
-
-
1
def d_o_s( p, ns, r )
-
#puts "IN DOS with #{ns.inspect}; ALREADY HAVE #{r.inspect}"
-
285
nt = nil
-
285
ns.each_index do |i|
-
589
n = ns[i]
-
#puts "P => #{p.inspect}"
-
589
x = expr( p.dclone, [ n ] )
-
589
nt = n.node_type
-
589
d_o_s( p, n.children, x ) if nt == :element or nt == :document and n.children.size > 0
-
589
r.concat(x) if x.size > 0
-
end
-
end
-
-
-
# Reorders an array of nodes so that they are in document order
-
# It tries to do this efficiently.
-
#
-
# FIXME: I need to get rid of this, but the issue is that most of the XPath
-
# interpreter functions as a filter, which means that we lose context going
-
# in and out of function calls. If I knew what the index of the nodes was,
-
# I wouldn't have to do this. Maybe add a document IDX for each node?
-
# Problems with mutable documents. Or, rewrite everything.
-
1
def document_order( array_of_nodes )
-
19
new_arry = []
-
19
array_of_nodes.each { |node|
-
19
node_idx = []
-
19
np = node.node_type == :attribute ? node.element : node
-
19
while np.parent and np.parent.node_type == :element
-
19
node_idx << np.parent.index( np )
-
19
np = np.parent
-
end
-
19
new_arry << [ node_idx.reverse, node ]
-
}
-
#puts "new_arry = #{new_arry.inspect}"
-
38
new_arry.sort{ |s1, s2| s1[0] <=> s2[0] }.collect{ |s| s[1] }
-
end
-
-
-
1
def recurse( nodeset, &block )
-
for node in nodeset
-
yield node
-
recurse( node, &block ) if node.node_type == :element
-
end
-
end
-
-
-
-
# Builds a nodeset of all of the preceding nodes of the supplied node,
-
# in reverse document order
-
# preceding:: includes every element in the document that precedes this node,
-
# except for ancestors
-
1
def preceding( node )
-
#puts "IN PRECEDING"
-
ancestors = []
-
p = node.parent
-
while p
-
ancestors << p
-
p = p.parent
-
end
-
-
acc = []
-
p = preceding_node_of( node )
-
#puts "P = #{p.inspect}"
-
while p
-
if ancestors.include? p
-
ancestors.delete(p)
-
else
-
acc << p
-
end
-
p = preceding_node_of( p )
-
#puts "P = #{p.inspect}"
-
end
-
acc
-
end
-
-
1
def preceding_node_of( node )
-
#puts "NODE: #{node.inspect}"
-
#puts "PREVIOUS NODE: #{node.previous_sibling_node.inspect}"
-
#puts "PARENT NODE: #{node.parent}"
-
psn = node.previous_sibling_node
-
if psn.nil?
-
if node.parent.nil? or node.parent.class == Document
-
return nil
-
end
-
return node.parent
-
#psn = preceding_node_of( node.parent )
-
end
-
while psn and psn.kind_of? Element and psn.children.size > 0
-
psn = psn.children[-1]
-
end
-
psn
-
end
-
-
1
def following( node )
-
#puts "IN PRECEDING"
-
acc = []
-
p = next_sibling_node( node )
-
#puts "P = #{p.inspect}"
-
while p
-
acc << p
-
p = following_node_of( p )
-
#puts "P = #{p.inspect}"
-
end
-
acc
-
end
-
-
1
def following_node_of( node )
-
#puts "NODE: #{node.inspect}"
-
#puts "PREVIOUS NODE: #{node.previous_sibling_node.inspect}"
-
#puts "PARENT NODE: #{node.parent}"
-
if node.kind_of? Element and node.children.size > 0
-
return node.children[0]
-
end
-
return next_sibling_node(node)
-
end
-
-
1
def next_sibling_node(node)
-
psn = node.next_sibling_node
-
while psn.nil?
-
if node.parent.nil? or node.parent.class == Document
-
return nil
-
end
-
node = node.parent
-
psn = node.next_sibling_node
-
#puts "psn = #{psn.inspect}"
-
end
-
return psn
-
end
-
-
1
def norm b
-
case b
-
when true, false
-
return b
-
when 'true', 'false'
-
return Functions::boolean( b )
-
when /^\d+(\.\d+)?$/
-
return Functions::number( b )
-
else
-
return Functions::string( b )
-
end
-
end
-
-
1
def equality_relational_compare( set1, op, set2 )
-
#puts "EQ_REL_COMP(#{set1.inspect} #{op.inspect} #{set2.inspect})"
-
if set1.kind_of? Array and set2.kind_of? Array
-
#puts "#{set1.size} & #{set2.size}"
-
if set1.size == 1 and set2.size == 1
-
set1 = set1[0]
-
set2 = set2[0]
-
elsif set1.size == 0 or set2.size == 0
-
nd = set1.size==0 ? set2 : set1
-
rv = nd.collect { |il| compare( il, op, nil ) }
-
#puts "RV = #{rv.inspect}"
-
return rv
-
else
-
res = []
-
SyncEnumerator.new( set1, set2 ).each { |i1, i2|
-
#puts "i1 = #{i1.inspect} (#{i1.class.name})"
-
#puts "i2 = #{i2.inspect} (#{i2.class.name})"
-
i1 = norm( i1 )
-
i2 = norm( i2 )
-
res << compare( i1, op, i2 )
-
}
-
return res
-
end
-
end
-
#puts "EQ_REL_COMP: #{set1.inspect} (#{set1.class.name}), #{op}, #{set2.inspect} (#{set2.class.name})"
-
#puts "COMPARING VALUES"
-
# If one is nodeset and other is number, compare number to each item
-
# in nodeset s.t. number op number(string(item))
-
# If one is nodeset and other is string, compare string to each item
-
# in nodeset s.t. string op string(item)
-
# If one is nodeset and other is boolean, compare boolean to each item
-
# in nodeset s.t. boolean op boolean(item)
-
if set1.kind_of? Array or set2.kind_of? Array
-
#puts "ISA ARRAY"
-
if set1.kind_of? Array
-
a = set1
-
b = set2
-
else
-
a = set2
-
b = set1
-
end
-
-
case b
-
when true, false
-
return a.collect {|v| compare( Functions::boolean(v), op, b ) }
-
when Numeric
-
return a.collect {|v| compare( Functions::number(v), op, b )}
-
when /^\d+(\.\d+)?$/
-
b = Functions::number( b )
-
#puts "B = #{b.inspect}"
-
return a.collect {|v| compare( Functions::number(v), op, b )}
-
else
-
#puts "Functions::string( #{b}(#{b.class.name}) ) = #{Functions::string(b)}"
-
b = Functions::string( b )
-
return a.collect { |v| compare( Functions::string(v), op, b ) }
-
end
-
else
-
# If neither is nodeset,
-
# If op is = or !=
-
# If either boolean, convert to boolean
-
# If either number, convert to number
-
# Else, convert to string
-
# Else
-
# Convert both to numbers and compare
-
s1 = set1.to_s
-
s2 = set2.to_s
-
#puts "EQ_REL_COMP: #{set1}=>#{s1}, #{set2}=>#{s2}"
-
if s1 == 'true' or s1 == 'false' or s2 == 'true' or s2 == 'false'
-
#puts "Functions::boolean(#{set1})=>#{Functions::boolean(set1)}"
-
#puts "Functions::boolean(#{set2})=>#{Functions::boolean(set2)}"
-
set1 = Functions::boolean( set1 )
-
set2 = Functions::boolean( set2 )
-
else
-
if op == :eq or op == :neq
-
if s1 =~ /^\d+(\.\d+)?$/ or s2 =~ /^\d+(\.\d+)?$/
-
set1 = Functions::number( s1 )
-
set2 = Functions::number( s2 )
-
else
-
set1 = Functions::string( set1 )
-
set2 = Functions::string( set2 )
-
end
-
else
-
set1 = Functions::number( set1 )
-
set2 = Functions::number( set2 )
-
end
-
end
-
#puts "EQ_REL_COMP: #{set1} #{op} #{set2}"
-
#puts ">>> #{compare( set1, op, set2 )}"
-
return compare( set1, op, set2 )
-
end
-
return false
-
end
-
-
1
def compare a, op, b
-
#puts "COMPARE #{a.inspect}(#{a.class.name}) #{op} #{b.inspect}(#{b.class.name})"
-
case op
-
when :eq
-
a == b
-
when :neq
-
a != b
-
when :lt
-
a < b
-
when :lteq
-
a <= b
-
when :gt
-
a > b
-
when :gteq
-
a >= b
-
when :and
-
a and b
-
when :or
-
a or b
-
else
-
false
-
end
-
end
-
end
-
end
-
# Copyright (c) 2003, 2004 Jim Weirich, 2009 Eric Hodel
-
#
-
# Permission is hereby granted, free of charge, to any person obtaining
-
# a copy of this software and associated documentation files (the
-
# "Software"), to deal in the Software without restriction, including
-
# without limitation the rights to use, copy, modify, merge, publish,
-
# distribute, sublicense, and/or sell copies of the Software, and to
-
# permit persons to whom the Software is furnished to do so, subject to
-
# the following conditions:
-
#
-
# The above copyright notice and this permission notice shall be
-
# included in all copies or substantial portions of the Software.
-
#
-
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
-
# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
-
# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
-
# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
-
# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
-
# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
-
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
-
-
1
require 'rubygems'
-
1
begin
-
1
gem 'rake'
-
rescue Gem::LoadError
-
end
-
-
1
require 'rake/packagetask'
-
-
##
-
# Create a package based upon a Gem::Specification. Gem packages, as well as
-
# zip files and tar/gzipped packages can be produced by this task.
-
#
-
# In addition to the Rake targets generated by Rake::PackageTask, a
-
# Gem::PackageTask will also generate the following tasks:
-
#
-
# [<b>"<em>package_dir</em>/<em>name</em>-<em>version</em>.gem"</b>]
-
# Create a RubyGems package with the given name and version.
-
#
-
# Example using a Gem::Specification:
-
#
-
# require 'rubygems'
-
# require 'rubygems/package_task'
-
#
-
# spec = Gem::Specification.new do |s|
-
# s.platform = Gem::Platform::RUBY
-
# s.summary = "Ruby based make-like utility."
-
# s.name = 'rake'
-
# s.version = PKG_VERSION
-
# s.requirements << 'none'
-
# s.require_path = 'lib'
-
# s.autorequire = 'rake'
-
# s.files = PKG_FILES
-
# s.description = <<-EOF
-
# Rake is a Make-like program implemented in Ruby. Tasks
-
# and dependencies are specified in standard Ruby syntax.
-
# EOF
-
# end
-
#
-
# Gem::PackageTask.new(spec) do |pkg|
-
# pkg.need_zip = true
-
# pkg.need_tar = true
-
# end
-
-
1
class Gem::PackageTask < Rake::PackageTask
-
-
##
-
# Ruby Gem::Specification containing the metadata for this package. The
-
# name, version and package_files are automatically determined from the
-
# gemspec and don't need to be explicitly provided.
-
-
1
attr_accessor :gem_spec
-
-
##
-
# Create a Gem Package task library. Automatically define the gem if a
-
# block is given. If no block is supplied, then #define needs to be called
-
# to define the task.
-
-
1
def initialize(gem_spec)
-
1
init gem_spec
-
1
yield self if block_given?
-
1
define if block_given?
-
end
-
-
##
-
# Initialization tasks without the "yield self" or define operations.
-
-
1
def init(gem)
-
1
super gem.full_name, :noversion
-
1
@gem_spec = gem
-
1
@package_files += gem_spec.files if gem_spec.files
-
end
-
-
##
-
# Create the Rake tasks and actions specified by this Gem::PackageTask.
-
# (+define+ is automatically called if a block is given to +new+).
-
-
1
def define
-
1
super
-
-
1
task :package => [:gem]
-
-
1
gem_file = File.basename gem_spec.cache_file
-
1
gem_path = File.join package_dir, gem_file
-
1
gem_dir = File.join package_dir, gem_spec.full_name
-
-
1
desc "Build the gem file #{gem_file}"
-
1
task :gem => [gem_path]
-
-
1
trace = Rake.application.options.trace
-
1
Gem.configuration.verbose = trace
-
-
1
file gem_path => [package_dir, gem_dir] + @gem_spec.files do
-
chdir(gem_dir) do
-
when_writing "Creating #{gem_spec.file_name}" do
-
Gem::Builder.new(gem_spec).build
-
verbose trace do
-
mv gem_file, '..'
-
end
-
end
-
end
-
end
-
end
-
-
end
-
-
# = Secure random number generator interface.
-
#
-
# This library is an interface for secure random number generator which is
-
# suitable for generating session key in HTTP cookies, etc.
-
#
-
# It supports following secure random number generators.
-
#
-
# * openssl
-
# * /dev/urandom
-
# * Win32
-
#
-
# == Example
-
#
-
# # random hexadecimal string.
-
# p SecureRandom.hex(10) #=> "52750b30ffbc7de3b362"
-
# p SecureRandom.hex(10) #=> "92b15d6c8dc4beb5f559"
-
# p SecureRandom.hex(11) #=> "6aca1b5c58e4863e6b81b8"
-
# p SecureRandom.hex(12) #=> "94b2fff3e7fd9b9c391a2306"
-
# p SecureRandom.hex(13) #=> "39b290146bea6ce975c37cfc23"
-
# ...
-
#
-
# # random base64 string.
-
# p SecureRandom.base64(10) #=> "EcmTPZwWRAozdA=="
-
# p SecureRandom.base64(10) #=> "9b0nsevdwNuM/w=="
-
# p SecureRandom.base64(10) #=> "KO1nIU+p9DKxGg=="
-
# p SecureRandom.base64(11) #=> "l7XEiFja+8EKEtY="
-
# p SecureRandom.base64(12) #=> "7kJSM/MzBJI+75j8"
-
# p SecureRandom.base64(13) #=> "vKLJ0tXBHqQOuIcSIg=="
-
# ...
-
#
-
# # random binary string.
-
# p SecureRandom.random_bytes(10) #=> "\016\t{\370g\310pbr\301"
-
# p SecureRandom.random_bytes(10) #=> "\323U\030TO\234\357\020\a\337"
-
# ...
-
-
1
begin
-
1
require 'openssl'
-
rescue LoadError
-
end
-
-
1
module SecureRandom
-
# SecureRandom.random_bytes generates a random binary string.
-
#
-
# The argument _n_ specifies the length of the result string.
-
#
-
# If _n_ is not specified, 16 is assumed.
-
# It may be larger in future.
-
#
-
# The result may contain any byte: "\x00" - "\xff".
-
#
-
# p SecureRandom.random_bytes #=> "\xD8\\\xE0\xF4\r\xB2\xFC*WM\xFF\x83\x18\xF45\xB6"
-
# p SecureRandom.random_bytes #=> "m\xDC\xFC/\a\x00Uf\xB2\xB2P\xBD\xFF6S\x97"
-
#
-
# If secure random number generator is not available,
-
# NotImplementedError is raised.
-
1
def self.random_bytes(n=nil)
-
15
n ||= 16
-
-
15
if defined? OpenSSL::Random
-
15
@pid = 0 if !defined?(@pid)
-
15
pid = $$
-
15
if @pid != pid
-
1
now = Time.now
-
1
ary = [now.to_i, now.nsec, @pid, pid]
-
1
OpenSSL::Random.seed(ary.to_s)
-
1
@pid = pid
-
end
-
15
return OpenSSL::Random.random_bytes(n)
-
end
-
-
if !defined?(@has_urandom) || @has_urandom
-
flags = File::RDONLY
-
flags |= File::NONBLOCK if defined? File::NONBLOCK
-
flags |= File::NOCTTY if defined? File::NOCTTY
-
begin
-
File.open("/dev/urandom", flags) {|f|
-
unless f.stat.chardev?
-
raise Errno::ENOENT
-
end
-
@has_urandom = true
-
ret = f.readpartial(n)
-
if ret.length != n
-
raise NotImplementedError, "Unexpected partial read from random device"
-
end
-
return ret
-
}
-
rescue Errno::ENOENT
-
@has_urandom = false
-
end
-
end
-
-
if !defined?(@has_win32)
-
begin
-
require 'Win32API'
-
-
crypt_acquire_context = Win32API.new("advapi32", "CryptAcquireContext", 'PPPII', 'L')
-
@crypt_gen_random = Win32API.new("advapi32", "CryptGenRandom", 'LIP', 'L')
-
-
hProvStr = " " * 4
-
prov_rsa_full = 1
-
crypt_verifycontext = 0xF0000000
-
-
if crypt_acquire_context.call(hProvStr, nil, nil, prov_rsa_full, crypt_verifycontext) == 0
-
raise SystemCallError, "CryptAcquireContext failed: #{lastWin32ErrorMessage}"
-
end
-
@hProv, = hProvStr.unpack('L')
-
-
@has_win32 = true
-
rescue LoadError
-
@has_win32 = false
-
end
-
end
-
if @has_win32
-
bytes = " ".force_encoding("ASCII-8BIT") * n
-
if @crypt_gen_random.call(@hProv, bytes.size, bytes) == 0
-
raise SystemCallError, "CryptGenRandom failed: #{lastWin32ErrorMessage}"
-
end
-
return bytes
-
end
-
-
raise NotImplementedError, "No random device"
-
end
-
-
# SecureRandom.hex generates a random hex string.
-
#
-
# The argument _n_ specifies the length of the random length.
-
# The length of the result string is twice of _n_.
-
#
-
# If _n_ is not specified, 16 is assumed.
-
# It may be larger in future.
-
#
-
# The result may contain 0-9 and a-f.
-
#
-
# p SecureRandom.hex #=> "eb693ec8252cd630102fd0d0fb7c3485"
-
# p SecureRandom.hex #=> "91dc3bfb4de5b11d029d376634589b61"
-
#
-
# If secure random number generator is not available,
-
# NotImplementedError is raised.
-
1
def self.hex(n=nil)
-
15
random_bytes(n).unpack("H*")[0]
-
end
-
-
# SecureRandom.base64 generates a random base64 string.
-
#
-
# The argument _n_ specifies the length of the random length.
-
# The length of the result string is about 4/3 of _n_.
-
#
-
# If _n_ is not specified, 16 is assumed.
-
# It may be larger in future.
-
#
-
# The result may contain A-Z, a-z, 0-9, "+", "/" and "=".
-
#
-
# p SecureRandom.base64 #=> "/2BuBuLf3+WfSKyQbRcc/A=="
-
# p SecureRandom.base64 #=> "6BbW0pxO0YENxn38HMUbcQ=="
-
#
-
# If secure random number generator is not available,
-
# NotImplementedError is raised.
-
#
-
# See RFC 3548 for the definition of base64.
-
1
def self.base64(n=nil)
-
[random_bytes(n)].pack("m*").delete("\n")
-
end
-
-
# SecureRandom.urlsafe_base64 generates a random URL-safe base64 string.
-
#
-
# The argument _n_ specifies the length of the random length.
-
# The length of the result string is about 4/3 of _n_.
-
#
-
# If _n_ is not specified, 16 is assumed.
-
# It may be larger in future.
-
#
-
# The boolean argument _padding_ specifies the padding.
-
# If it is false or nil, padding is not generated.
-
# Otherwise padding is generated.
-
# By default, padding is not generated because "=" may be used as a URL delimiter.
-
#
-
# The result may contain A-Z, a-z, 0-9, "-" and "_".
-
# "=" is also used if _padding_ is true.
-
#
-
# p SecureRandom.urlsafe_base64 #=> "b4GOKm4pOYU_-BOXcrUGDg"
-
# p SecureRandom.urlsafe_base64 #=> "UZLdOkzop70Ddx-IJR0ABg"
-
#
-
# p SecureRandom.urlsafe_base64(nil, true) #=> "i0XQ-7gglIsHGV2_BNPrdQ=="
-
# p SecureRandom.urlsafe_base64(nil, true) #=> "-M8rLhr7JEpJlqFGUMmOxg=="
-
#
-
# If secure random number generator is not available,
-
# NotImplementedError is raised.
-
#
-
# See RFC 3548 for the definition of URL-safe base64.
-
1
def self.urlsafe_base64(n=nil, padding=false)
-
s = [random_bytes(n)].pack("m*")
-
s.delete!("\n")
-
s.tr!("+/", "-_")
-
s.delete!("=") if !padding
-
s
-
end
-
-
# SecureRandom.random_number generates a random number.
-
#
-
# If a positive integer is given as _n_,
-
# SecureRandom.random_number returns an integer:
-
# 0 <= SecureRandom.random_number(n) < n.
-
#
-
# p SecureRandom.random_number(100) #=> 15
-
# p SecureRandom.random_number(100) #=> 88
-
#
-
# If 0 is given or an argument is not given,
-
# SecureRandom.random_number returns a float:
-
# 0.0 <= SecureRandom.random_number() < 1.0.
-
#
-
# p SecureRandom.random_number #=> 0.596506046187744
-
# p SecureRandom.random_number #=> 0.350621695741409
-
#
-
1
def self.random_number(n=0)
-
if 0 < n
-
hex = n.to_s(16)
-
hex = '0' + hex if (hex.length & 1) == 1
-
bin = [hex].pack("H*")
-
mask = bin[0].ord
-
mask |= mask >> 1
-
mask |= mask >> 2
-
mask |= mask >> 4
-
begin
-
rnd = SecureRandom.random_bytes(bin.length)
-
rnd[0] = (rnd[0].ord & mask).chr
-
end until rnd < bin
-
rnd.unpack("H*")[0].hex
-
else
-
# assumption: Float::MANT_DIG <= 64
-
i64 = SecureRandom.random_bytes(8).unpack("Q")[0]
-
Math.ldexp(i64 >> (64-Float::MANT_DIG), -Float::MANT_DIG)
-
end
-
end
-
-
# SecureRandom.uuid generates a v4 random UUID (Universally Unique IDentifier).
-
#
-
# p SecureRandom.uuid #=> "2d931510-d99f-494a-8c67-87feb05e1594"
-
# p SecureRandom.uuid #=> "bad85eb9-0713-4da7-8d36-07a8e4b00eab"
-
# p SecureRandom.uuid #=> "62936e70-1815-439b-bf89-8492855a7e6b"
-
#
-
# The version 4 UUID is purely random (except the version).
-
# It doesn't contain meaningful information such as MAC address, time, etc.
-
#
-
# See RFC 4122 for details of UUID.
-
#
-
1
def self.uuid
-
ary = self.random_bytes(16).unpack("NnnnnN")
-
ary[2] = (ary[2] & 0x0fff) | 0x4000
-
ary[3] = (ary[3] & 0x3fff) | 0x8000
-
"%08x-%04x-%04x-%04x-%04x%08x" % ary
-
end
-
-
# Following code is based on David Garamond's GUID library for Ruby.
-
1
def self.lastWin32ErrorMessage # :nodoc:
-
get_last_error = Win32API.new("kernel32", "GetLastError", '', 'L')
-
format_message = Win32API.new("kernel32", "FormatMessageA", 'LPLLPLPPPPPPPP', 'L')
-
format_message_ignore_inserts = 0x00000200
-
format_message_from_system = 0x00001000
-
-
code = get_last_error.call
-
msg = "\0" * 1024
-
len = format_message.call(format_message_ignore_inserts + format_message_from_system, 0, code, 0, msg, 1024, nil, nil, nil, nil, nil, nil, nil, nil)
-
msg[0, len].tr("\r", '').chomp
-
end
-
end
-
1
require 'socket.so'
-
-
1
class Addrinfo
-
# creates an Addrinfo object from the arguments.
-
#
-
# The arguments are interpreted as similar to self.
-
#
-
# Addrinfo.tcp("0.0.0.0", 4649).family_addrinfo("www.ruby-lang.org", 80)
-
# #=> #<Addrinfo: 221.186.184.68:80 TCP (www.ruby-lang.org:80)>
-
#
-
# Addrinfo.unix("/tmp/sock").family_addrinfo("/tmp/sock2")
-
# #=> #<Addrinfo: /tmp/sock2 SOCK_STREAM>
-
#
-
1
def family_addrinfo(*args)
-
if args.empty?
-
raise ArgumentError, "no address specified"
-
elsif Addrinfo === args.first
-
raise ArgumentError, "too many arguments" if args.length != 1
-
elsif self.ip?
-
raise ArgumentError, "IP address needs host and port but #{args.length} arguments given" if args.length != 2
-
host, port = args
-
Addrinfo.getaddrinfo(host, port, self.pfamily, self.socktype, self.protocol)[0]
-
elsif self.unix?
-
raise ArgumentError, "UNIX socket needs single path argument but #{args.length} arguments given" if args.length != 1
-
path, = args
-
Addrinfo.unix(path)
-
else
-
raise ArgumentError, "unexpected family"
-
end
-
end
-
-
# creates a new Socket connected to the address of +local_addrinfo+.
-
#
-
# If no arguments are given, the address of the socket is not bound.
-
#
-
# If a block is given the created socket is yielded for each address.
-
#
-
1
def connect_internal(local_addrinfo) # :yields: socket
-
sock = Socket.new(self.pfamily, self.socktype, self.protocol)
-
begin
-
sock.ipv6only! if self.ipv6?
-
sock.bind local_addrinfo if local_addrinfo
-
sock.connect(self)
-
if block_given?
-
yield sock
-
else
-
sock
-
end
-
ensure
-
sock.close if !sock.closed? && (block_given? || $!)
-
end
-
end
-
1
private :connect_internal
-
-
# creates a socket connected to the address of self.
-
#
-
# If one or more arguments given as _local_addr_args_,
-
# it is used as the local address of the socket.
-
# _local_addr_args_ is given for family_addrinfo to obtain actual address.
-
#
-
# If no arguments given, the local address of the socket is not bound.
-
#
-
# If a block is given, it is called with the socket and the value of the block is returned.
-
# The socket is returned otherwise.
-
#
-
# Addrinfo.tcp("www.ruby-lang.org", 80).connect_from("0.0.0.0", 4649) {|s|
-
# s.print "GET / HTTP/1.0\r\nHost: www.ruby-lang.org\r\n\r\n"
-
# puts s.read
-
# }
-
#
-
# # Addrinfo object can be taken for the argument.
-
# Addrinfo.tcp("www.ruby-lang.org", 80).connect_from(Addrinfo.tcp("0.0.0.0", 4649)) {|s|
-
# s.print "GET / HTTP/1.0\r\nHost: www.ruby-lang.org\r\n\r\n"
-
# puts s.read
-
# }
-
#
-
1
def connect_from(*local_addr_args, &block)
-
connect_internal(family_addrinfo(*local_addr_args), &block)
-
end
-
-
# creates a socket connected to the address of self.
-
#
-
# If a block is given, it is called with the socket and the value of the block is returned.
-
# The socket is returned otherwise.
-
#
-
# Addrinfo.tcp("www.ruby-lang.org", 80).connect {|s|
-
# s.print "GET / HTTP/1.0\r\nHost: www.ruby-lang.org\r\n\r\n"
-
# puts s.read
-
# }
-
#
-
1
def connect(&block)
-
connect_internal(nil, &block)
-
end
-
-
# creates a socket connected to _remote_addr_args_ and bound to self.
-
#
-
# If a block is given, it is called with the socket and the value of the block is returned.
-
# The socket is returned otherwise.
-
#
-
# Addrinfo.tcp("0.0.0.0", 4649).connect_to("www.ruby-lang.org", 80) {|s|
-
# s.print "GET / HTTP/1.0\r\nHost: www.ruby-lang.org\r\n\r\n"
-
# puts s.read
-
# }
-
#
-
1
def connect_to(*remote_addr_args, &block)
-
remote_addrinfo = family_addrinfo(*remote_addr_args)
-
remote_addrinfo.send(:connect_internal, self, &block)
-
end
-
-
# creates a socket bound to self.
-
#
-
# If a block is given, it is called with the socket and the value of the block is returned.
-
# The socket is returned otherwise.
-
#
-
# Addrinfo.udp("0.0.0.0", 9981).bind {|s|
-
# s.local_address.connect {|s| s.send "hello", 0 }
-
# p s.recv(10) #=> "hello"
-
# }
-
#
-
1
def bind
-
sock = Socket.new(self.pfamily, self.socktype, self.protocol)
-
begin
-
sock.ipv6only! if self.ipv6?
-
sock.setsockopt(:SOCKET, :REUSEADDR, 1)
-
sock.bind(self)
-
if block_given?
-
yield sock
-
else
-
sock
-
end
-
ensure
-
sock.close if !sock.closed? && (block_given? || $!)
-
end
-
end
-
-
# creates a listening socket bound to self.
-
1
def listen(backlog=5)
-
sock = Socket.new(self.pfamily, self.socktype, self.protocol)
-
begin
-
sock.ipv6only! if self.ipv6?
-
sock.setsockopt(:SOCKET, :REUSEADDR, 1)
-
sock.bind(self)
-
sock.listen(backlog)
-
if block_given?
-
yield sock
-
else
-
sock
-
end
-
ensure
-
sock.close if !sock.closed? && (block_given? || $!)
-
end
-
end
-
-
# iterates over the list of Addrinfo objects obtained by Addrinfo.getaddrinfo.
-
#
-
# Addrinfo.foreach(nil, 80) {|x| p x }
-
# #=> #<Addrinfo: 127.0.0.1:80 TCP (:80)>
-
# # #<Addrinfo: 127.0.0.1:80 UDP (:80)>
-
# # #<Addrinfo: [::1]:80 TCP (:80)>
-
# # #<Addrinfo: [::1]:80 UDP (:80)>
-
#
-
1
def self.foreach(nodename, service, family=nil, socktype=nil, protocol=nil, flags=nil, &block)
-
Addrinfo.getaddrinfo(nodename, service, family, socktype, protocol, flags).each(&block)
-
end
-
end
-
-
1
class BasicSocket < IO
-
# Returns an address of the socket suitable for connect in the local machine.
-
#
-
# This method returns _self_.local_address, except following condition.
-
#
-
# - IPv4 unspecified address (0.0.0.0) is replaced by IPv4 loopback address (127.0.0.1).
-
# - IPv6 unspecified address (::) is replaced by IPv6 loopback address (::1).
-
#
-
# If the local address is not suitable for connect, SocketError is raised.
-
# IPv4 and IPv6 address which port is 0 is not suitable for connect.
-
# Unix domain socket which has no path is not suitable for connect.
-
#
-
# Addrinfo.tcp("0.0.0.0", 0).listen {|serv|
-
# p serv.connect_address #=> #<Addrinfo: 127.0.0.1:53660 TCP>
-
# serv.connect_address.connect {|c|
-
# s, _ = serv.accept
-
# p [c, s] #=> [#<Socket:fd 4>, #<Socket:fd 6>]
-
# }
-
# }
-
#
-
1
def connect_address
-
addr = local_address
-
afamily = addr.afamily
-
if afamily == Socket::AF_INET
-
raise SocketError, "unbound IPv4 socket" if addr.ip_port == 0
-
if addr.ip_address == "0.0.0.0"
-
addr = Addrinfo.new(["AF_INET", addr.ip_port, nil, "127.0.0.1"], addr.pfamily, addr.socktype, addr.protocol)
-
end
-
elsif defined?(Socket::AF_INET6) && afamily == Socket::AF_INET6
-
raise SocketError, "unbound IPv6 socket" if addr.ip_port == 0
-
if addr.ip_address == "::"
-
addr = Addrinfo.new(["AF_INET6", addr.ip_port, nil, "::1"], addr.pfamily, addr.socktype, addr.protocol)
-
elsif addr.ip_address == "0.0.0.0" # MacOS X 10.4 returns "a.b.c.d" for IPv4-mapped IPv6 address.
-
addr = Addrinfo.new(["AF_INET6", addr.ip_port, nil, "::1"], addr.pfamily, addr.socktype, addr.protocol)
-
elsif addr.ip_address == "::ffff:0.0.0.0" # MacOS X 10.6 returns "::ffff:a.b.c.d" for IPv4-mapped IPv6 address.
-
addr = Addrinfo.new(["AF_INET6", addr.ip_port, nil, "::1"], addr.pfamily, addr.socktype, addr.protocol)
-
end
-
elsif defined?(Socket::AF_UNIX) && afamily == Socket::AF_UNIX
-
raise SocketError, "unbound Unix socket" if addr.unix_path == ""
-
end
-
addr
-
end
-
end
-
-
1
class Socket < BasicSocket
-
# enable the socket option IPV6_V6ONLY if IPV6_V6ONLY is available.
-
1
def ipv6only!
-
if defined? Socket::IPV6_V6ONLY
-
self.setsockopt(:IPV6, :V6ONLY, 1)
-
end
-
end
-
-
# creates a new socket object connected to host:port using TCP/IP.
-
#
-
# If local_host:local_port is given,
-
# the socket is bound to it.
-
#
-
# If a block is given, the block is called with the socket.
-
# The value of the block is returned.
-
# The socket is closed when this method returns.
-
#
-
# If no block is given, the socket is returned.
-
#
-
# Socket.tcp("www.ruby-lang.org", 80) {|sock|
-
# sock.print "GET / HTTP/1.0\r\nHost: www.ruby-lang.org\r\n\r\n"
-
# sock.close_write
-
# puts sock.read
-
# }
-
#
-
1
def self.tcp(host, port, local_host=nil, local_port=nil) # :yield: socket
-
last_error = nil
-
ret = nil
-
-
local_addr_list = nil
-
if local_host != nil || local_port != nil
-
local_addr_list = Addrinfo.getaddrinfo(local_host, local_port, nil, :STREAM, nil)
-
end
-
-
Addrinfo.foreach(host, port, nil, :STREAM) {|ai|
-
if local_addr_list
-
local_addr = local_addr_list.find {|local_ai| local_ai.afamily == ai.afamily }
-
next if !local_addr
-
else
-
local_addr = nil
-
end
-
begin
-
sock = local_addr ? ai.connect_from(local_addr) : ai.connect
-
rescue SystemCallError
-
last_error = $!
-
next
-
end
-
ret = sock
-
break
-
}
-
if !ret
-
if last_error
-
raise last_error
-
else
-
raise SocketError, "no appropriate local address"
-
end
-
end
-
if block_given?
-
begin
-
yield ret
-
ensure
-
ret.close if !ret.closed?
-
end
-
else
-
ret
-
end
-
end
-
-
# :stopdoc:
-
1
def self.ip_sockets_port0(ai_list, reuseaddr)
-
begin
-
sockets = []
-
port = nil
-
ai_list.each {|ai|
-
begin
-
s = Socket.new(ai.pfamily, ai.socktype, ai.protocol)
-
rescue SystemCallError
-
next
-
end
-
sockets << s
-
s.ipv6only! if ai.ipv6?
-
if reuseaddr
-
s.setsockopt(:SOCKET, :REUSEADDR, 1)
-
end
-
if !port
-
s.bind(ai)
-
port = s.local_address.ip_port
-
else
-
s.bind(ai.family_addrinfo(ai.ip_address, port))
-
end
-
}
-
rescue Errno::EADDRINUSE
-
sockets.each {|s|
-
s.close
-
}
-
retry
-
end
-
sockets
-
ensure
-
sockets.each {|s| s.close if !s.closed? } if $!
-
end
-
1
class << self
-
1
private :ip_sockets_port0
-
end
-
-
1
def self.tcp_server_sockets_port0(host)
-
ai_list = Addrinfo.getaddrinfo(host, 0, nil, :STREAM, nil, Socket::AI_PASSIVE)
-
sockets = ip_sockets_port0(ai_list, true)
-
sockets.each {|s|
-
s.listen(5)
-
}
-
sockets
-
ensure
-
sockets.each {|s| s.close if !s.closed? } if $! && sockets
-
end
-
1
class << self
-
1
private :tcp_server_sockets_port0
-
end
-
# :startdoc:
-
-
# creates TCP/IP server sockets for _host_ and _port_.
-
# _host_ is optional.
-
#
-
# If no block given,
-
# it returns an array of listening sockets.
-
#
-
# If a block is given, the block is called with the sockets.
-
# The value of the block is returned.
-
# The socket is closed when this method returns.
-
#
-
# If _port_ is 0, actual port number is choosen dynamically.
-
# However all sockets in the result has same port number.
-
#
-
# # tcp_server_sockets returns two sockets.
-
# sockets = Socket.tcp_server_sockets(1296)
-
# p sockets #=> [#<Socket:fd 3>, #<Socket:fd 4>]
-
#
-
# # The sockets contains IPv6 and IPv4 sockets.
-
# sockets.each {|s| p s.local_address }
-
# #=> #<Addrinfo: [::]:1296 TCP>
-
# # #<Addrinfo: 0.0.0.0:1296 TCP>
-
#
-
# # IPv6 and IPv4 socket has same port number, 53114, even if it is choosen dynamically.
-
# sockets = Socket.tcp_server_sockets(0)
-
# sockets.each {|s| p s.local_address }
-
# #=> #<Addrinfo: [::]:53114 TCP>
-
# # #<Addrinfo: 0.0.0.0:53114 TCP>
-
#
-
# # The block is called with the sockets.
-
# Socket.tcp_server_sockets(0) {|sockets|
-
# p sockets #=> [#<Socket:fd 3>, #<Socket:fd 4>]
-
# }
-
#
-
1
def self.tcp_server_sockets(host=nil, port)
-
if port == 0
-
sockets = tcp_server_sockets_port0(host)
-
else
-
begin
-
last_error = nil
-
sockets = []
-
Addrinfo.foreach(host, port, nil, :STREAM, nil, Socket::AI_PASSIVE) {|ai|
-
begin
-
s = ai.listen
-
rescue SystemCallError
-
last_error = $!
-
next
-
end
-
sockets << s
-
}
-
if sockets.empty?
-
raise last_error
-
end
-
ensure
-
sockets.each {|s| s.close if !s.closed? } if $!
-
end
-
end
-
if block_given?
-
begin
-
yield sockets
-
ensure
-
sockets.each {|s| s.close if !s.closed? }
-
end
-
else
-
sockets
-
end
-
end
-
-
# yield socket and client address for each a connection accepted via given sockets.
-
#
-
# The arguments are a list of sockets.
-
# The individual argument should be a socket or an array of sockets.
-
#
-
# This method yields the block sequentially.
-
# It means that the next connection is not accepted until the block returns.
-
# So concurrent mechanism, thread for example, should be used to service multiple clients at a time.
-
#
-
1
def self.accept_loop(*sockets) # :yield: socket, client_addrinfo
-
sockets.flatten!(1)
-
if sockets.empty?
-
raise ArgumentError, "no sockets"
-
end
-
loop {
-
readable, _, _ = IO.select(sockets)
-
readable.each {|r|
-
begin
-
sock, addr = r.accept_nonblock
-
rescue IO::WaitReadable
-
next
-
end
-
yield sock, addr
-
}
-
}
-
end
-
-
# creates a TCP/IP server on _port_ and calls the block for each connection accepted.
-
# The block is called with a socket and a client_address as an Addrinfo object.
-
#
-
# If _host_ is specified, it is used with _port_ to determine the server addresses.
-
#
-
# The socket is *not* closed when the block returns.
-
# So application should close it explicitly.
-
#
-
# This method calls the block sequentially.
-
# It means that the next connection is not accepted until the block returns.
-
# So concurrent mechanism, thread for example, should be used to service multiple clients at a time.
-
#
-
# Note that Addrinfo.getaddrinfo is used to determine the server socket addresses.
-
# When Addrinfo.getaddrinfo returns two or more addresses,
-
# IPv4 and IPv6 address for example,
-
# all of them are used.
-
# Socket.tcp_server_loop succeeds if one socket can be used at least.
-
#
-
# # Sequential echo server.
-
# # It services only one client at a time.
-
# Socket.tcp_server_loop(16807) {|sock, client_addrinfo|
-
# begin
-
# IO.copy_stream(sock, sock)
-
# ensure
-
# sock.close
-
# end
-
# }
-
#
-
# # Threaded echo server
-
# # It services multiple clients at a time.
-
# # Note that it may accept connections too much.
-
# Socket.tcp_server_loop(16807) {|sock, client_addrinfo|
-
# Thread.new {
-
# begin
-
# IO.copy_stream(sock, sock)
-
# ensure
-
# sock.close
-
# end
-
# }
-
# }
-
#
-
1
def self.tcp_server_loop(host=nil, port, &b) # :yield: socket, client_addrinfo
-
tcp_server_sockets(host, port) {|sockets|
-
accept_loop(sockets, &b)
-
}
-
end
-
-
# :call-seq:
-
# Socket.udp_server_sockets([host, ] port)
-
#
-
# Creates UDP/IP sockets for a UDP server.
-
#
-
# If no block given, it returns an array of sockets.
-
#
-
# If a block is given, the block is called with the sockets.
-
# The value of the block is returned.
-
# The sockets are closed when this method returns.
-
#
-
# If _port_ is zero, some port is choosen.
-
# But the choosen port is used for the all sockets.
-
#
-
# # UDP/IP echo server
-
# Socket.udp_server_sockets(0) {|sockets|
-
# p sockets.first.local_address.ip_port #=> 32963
-
# Socket.udp_server_loop_on(sockets) {|msg, msg_src|
-
# msg_src.reply msg
-
# }
-
# }
-
#
-
1
def self.udp_server_sockets(host=nil, port)
-
last_error = nil
-
sockets = []
-
-
ipv6_recvpktinfo = nil
-
if defined? Socket::AncillaryData
-
if defined? Socket::IPV6_RECVPKTINFO # RFC 3542
-
ipv6_recvpktinfo = Socket::IPV6_RECVPKTINFO
-
elsif defined? Socket::IPV6_PKTINFO # RFC 2292
-
ipv6_recvpktinfo = Socket::IPV6_PKTINFO
-
end
-
end
-
-
local_addrs = Socket.ip_address_list
-
-
ip_list = []
-
Addrinfo.foreach(host, port, nil, :DGRAM, nil, Socket::AI_PASSIVE) {|ai|
-
if ai.ipv4? && ai.ip_address == "0.0.0.0"
-
local_addrs.each {|a|
-
next if !a.ipv4?
-
ip_list << Addrinfo.new(a.to_sockaddr, :INET, :DGRAM, 0);
-
}
-
elsif ai.ipv6? && ai.ip_address == "::" && !ipv6_recvpktinfo
-
local_addrs.each {|a|
-
next if !a.ipv6?
-
ip_list << Addrinfo.new(a.to_sockaddr, :INET6, :DGRAM, 0);
-
}
-
else
-
ip_list << ai
-
end
-
}
-
-
if port == 0
-
sockets = ip_sockets_port0(ip_list, false)
-
else
-
ip_list.each {|ip|
-
ai = Addrinfo.udp(ip.ip_address, port)
-
begin
-
s = ai.bind
-
rescue SystemCallError
-
last_error = $!
-
next
-
end
-
sockets << s
-
}
-
if sockets.empty?
-
raise last_error
-
end
-
end
-
-
sockets.each {|s|
-
ai = s.local_address
-
if ipv6_recvpktinfo && ai.ipv6? && ai.ip_address == "::"
-
s.setsockopt(:IPV6, ipv6_recvpktinfo, 1)
-
end
-
}
-
-
if block_given?
-
begin
-
yield sockets
-
ensure
-
sockets.each {|s| s.close if !s.closed? } if sockets
-
end
-
else
-
sockets
-
end
-
end
-
-
# :call-seq:
-
# Socket.udp_server_recv(sockets) {|msg, msg_src| ... }
-
#
-
# Receive UDP/IP packets from the given _sockets_.
-
# For each packet received, the block is called.
-
#
-
# The block receives _msg_ and _msg_src_.
-
# _msg_ is a string which is the payload of the received packet.
-
# _msg_src_ is a Socket::UDPSource object which is used for reply.
-
#
-
# Socket.udp_server_loop can be implemented using this method as follows.
-
#
-
# udp_server_sockets(host, port) {|sockets|
-
# loop {
-
# readable, _, _ = IO.select(sockets)
-
# udp_server_recv(readable) {|msg, msg_src| ... }
-
# }
-
# }
-
#
-
1
def self.udp_server_recv(sockets)
-
sockets.each {|r|
-
begin
-
msg, sender_addrinfo, _, *controls = r.recvmsg_nonblock
-
rescue IO::WaitReadable
-
next
-
end
-
ai = r.local_address
-
if ai.ipv6? and pktinfo = controls.find {|c| c.cmsg_is?(:IPV6, :PKTINFO) }
-
ai = Addrinfo.udp(pktinfo.ipv6_pktinfo_addr.ip_address, ai.ip_port)
-
yield msg, UDPSource.new(sender_addrinfo, ai) {|reply_msg|
-
r.sendmsg reply_msg, 0, sender_addrinfo, pktinfo
-
}
-
else
-
yield msg, UDPSource.new(sender_addrinfo, ai) {|reply_msg|
-
r.send reply_msg, 0, sender_addrinfo
-
}
-
end
-
}
-
end
-
-
# :call-seq:
-
# Socket.udp_server_loop_on(sockets) {|msg, msg_src| ... }
-
#
-
# Run UDP/IP server loop on the given sockets.
-
#
-
# The return value of Socket.udp_server_sockets is appropriate for the argument.
-
#
-
# It calls the block for each message received.
-
#
-
1
def self.udp_server_loop_on(sockets, &b) # :yield: msg, msg_src
-
loop {
-
readable, _, _ = IO.select(sockets)
-
udp_server_recv(readable, &b)
-
}
-
end
-
-
# :call-seq:
-
# Socket.udp_server_loop(port) {|msg, msg_src| ... }
-
# Socket.udp_server_loop(host, port) {|msg, msg_src| ... }
-
#
-
# creates a UDP/IP server on _port_ and calls the block for each message arrived.
-
# The block is called with the message and its source information.
-
#
-
# This method allocates sockets internally using _port_.
-
# If _host_ is specified, it is used conjunction with _port_ to determine the server addresses.
-
#
-
# The _msg_ is a string.
-
#
-
# The _msg_src_ is a Socket::UDPSource object.
-
# It is used for reply.
-
#
-
# # UDP/IP echo server.
-
# Socket.udp_server_loop(9261) {|msg, msg_src|
-
# msg_src.reply msg
-
# }
-
#
-
1
def self.udp_server_loop(host=nil, port, &b) # :yield: message, message_source
-
udp_server_sockets(host, port) {|sockets|
-
udp_server_loop_on(sockets, &b)
-
}
-
end
-
-
# UDP/IP address information used by Socket.udp_server_loop.
-
1
class UDPSource
-
# +remote_adress+ is an Addrinfo object.
-
#
-
# +local_adress+ is an Addrinfo object.
-
#
-
# +reply_proc+ is a Proc used to send reply back to the source.
-
1
def initialize(remote_address, local_address, &reply_proc)
-
@remote_address = remote_address
-
@local_address = local_address
-
@reply_proc = reply_proc
-
end
-
-
# Address of the source
-
1
attr_reader :remote_address
-
-
# Local address
-
1
attr_reader :local_address
-
-
1
def inspect # :nodoc:
-
"\#<#{self.class}: #{@remote_address.inspect_sockaddr} to #{@local_address.inspect_sockaddr}>"
-
end
-
-
# Sends the String +msg+ to the source
-
1
def reply(msg)
-
@reply_proc.call msg
-
end
-
end
-
-
# creates a new socket connected to path using UNIX socket socket.
-
#
-
# If a block is given, the block is called with the socket.
-
# The value of the block is returned.
-
# The socket is closed when this method returns.
-
#
-
# If no block is given, the socket is returned.
-
#
-
# # talk to /tmp/sock socket.
-
# Socket.unix("/tmp/sock") {|sock|
-
# t = Thread.new { IO.copy_stream(sock, STDOUT) }
-
# IO.copy_stream(STDIN, sock)
-
# t.join
-
# }
-
#
-
1
def self.unix(path) # :yield: socket
-
addr = Addrinfo.unix(path)
-
sock = addr.connect
-
if block_given?
-
begin
-
yield sock
-
ensure
-
sock.close if !sock.closed?
-
end
-
else
-
sock
-
end
-
end
-
-
# creates a UNIX server socket on _path_
-
#
-
# If no block given, it returns a listening socket.
-
#
-
# If a block is given, it is called with the socket and the block value is returned.
-
# When the block exits, the socket is closed and the socket file is removed.
-
#
-
# socket = Socket.unix_server_socket("/tmp/s")
-
# p socket #=> #<Socket:fd 3>
-
# p socket.local_address #=> #<Addrinfo: /tmp/s SOCK_STREAM>
-
#
-
# Socket.unix_server_socket("/tmp/sock") {|s|
-
# p s #=> #<Socket:fd 3>
-
# p s.local_address #=> # #<Addrinfo: /tmp/sock SOCK_STREAM>
-
# }
-
#
-
1
def self.unix_server_socket(path)
-
begin
-
st = File.lstat(path)
-
rescue Errno::ENOENT
-
end
-
if st && st.socket? && st.owned?
-
File.unlink path
-
end
-
s = Addrinfo.unix(path).listen
-
if block_given?
-
begin
-
yield s
-
ensure
-
s.close if !s.closed?
-
File.unlink path
-
end
-
else
-
s
-
end
-
end
-
-
# creates a UNIX socket server on _path_.
-
# It calls the block for each socket accepted.
-
#
-
# If _host_ is specified, it is used with _port_ to determine the server ports.
-
#
-
# The socket is *not* closed when the block returns.
-
# So application should close it.
-
#
-
# This method deletes the socket file pointed by _path_ at first if
-
# the file is a socket file and it is owned by the user of the application.
-
# This is safe only if the directory of _path_ is not changed by a malicious user.
-
# So don't use /tmp/malicious-users-directory/socket.
-
# Note that /tmp/socket and /tmp/your-private-directory/socket is safe assuming that /tmp has sticky bit.
-
#
-
# # Sequential echo server.
-
# # It services only one client at a time.
-
# Socket.unix_server_loop("/tmp/sock") {|sock, client_addrinfo|
-
# begin
-
# IO.copy_stream(sock, sock)
-
# ensure
-
# sock.close
-
# end
-
# }
-
#
-
1
def self.unix_server_loop(path, &b) # :yield: socket, client_addrinfo
-
unix_server_socket(path) {|serv|
-
accept_loop(serv, &b)
-
}
-
end
-
-
end
-
-
#
-
# tempfile - manipulates temporary files
-
#
-
# $Id: tempfile.rb 33089 2011-08-26 23:54:49Z drbrain $
-
#
-
-
1
require 'delegate'
-
1
require 'tmpdir'
-
1
require 'thread'
-
-
# A utility class for managing temporary files. When you create a Tempfile
-
# object, it will create a temporary file with a unique filename. A Tempfile
-
# objects behaves just like a File object, and you can perform all the usual
-
# file operations on it: reading data, writing data, changing its permissions,
-
# etc. So although this class does not explicitly document all instance methods
-
# supported by File, you can in fact call any File instance method on a
-
# Tempfile object.
-
#
-
# == Synopsis
-
#
-
# require 'tempfile'
-
#
-
# file = Tempfile.new('foo')
-
# file.path # => A unique filename in the OS's temp directory,
-
# # e.g.: "/tmp/foo.24722.0"
-
# # This filename contains 'foo' in its basename.
-
# file.write("hello world")
-
# file.rewind
-
# file.read # => "hello world"
-
# file.close
-
# file.unlink # deletes the temp file
-
#
-
# == Good practices
-
#
-
# === Explicit close
-
#
-
# When a Tempfile object is garbage collected, or when the Ruby interpreter
-
# exits, its associated temporary file is automatically deleted. This means
-
# that's it's unnecessary to explicitly delete a Tempfile after use, though
-
# it's good practice to do so: not explicitly deleting unused Tempfiles can
-
# potentially leave behind large amounts of tempfiles on the filesystem
-
# until they're garbage collected. The existence of these temp files can make
-
# it harder to determine a new Tempfile filename.
-
#
-
# Therefore, one should always call #unlink or close in an ensure block, like
-
# this:
-
#
-
# file = Tempfile.new('foo')
-
# begin
-
# ...do something with file...
-
# ensure
-
# file.close
-
# file.unlink # deletes the temp file
-
# end
-
#
-
# === Unlink after creation
-
#
-
# On POSIX systems, it's possible to unlink a file right after creating it,
-
# and before closing it. This removes the filesystem entry without closing
-
# the file handle, so it ensures that only the processes that already had
-
# the file handle open can access the file's contents. It's strongly
-
# recommended that you do this if you do not want any other processes to
-
# be able to read from or write to the Tempfile, and you do not need to
-
# know the Tempfile's filename either.
-
#
-
# For example, a practical use case for unlink-after-creation would be this:
-
# you need a large byte buffer that's too large to comfortably fit in RAM,
-
# e.g. when you're writing a web server and you want to buffer the client's
-
# file upload data.
-
#
-
# Please refer to #unlink for more information and a code example.
-
#
-
# == Minor notes
-
#
-
# Tempfile's filename picking method is both thread-safe and inter-process-safe:
-
# it guarantees that no other threads or processes will pick the same filename.
-
#
-
# Tempfile itself however may not be entirely thread-safe. If you access the
-
# same Tempfile object from multiple threads then you should protect it with a
-
# mutex.
-
1
class Tempfile < DelegateClass(File)
-
1
MAX_TRY = 10 # :nodoc:
-
1
include Dir::Tmpname
-
-
# call-seq:
-
# new(basename, [tmpdir = Dir.tmpdir], [options])
-
#
-
# Creates a temporary file with permissions 0600 (= only readable and
-
# writable by the owner) and opens it with mode "w+".
-
#
-
# The +basename+ parameter is used to determine the name of the
-
# temporary file. You can either pass a String or an Array with
-
# 2 String elements. In the former form, the temporary file's base
-
# name will begin with the given string. In the latter form,
-
# the temporary file's base name will begin with the array's first
-
# element, and end with the second element. For example:
-
#
-
# file = Tempfile.new('hello')
-
# file.path # => something like: "/tmp/hello2843-8392-92849382--0"
-
#
-
# # Use the Array form to enforce an extension in the filename:
-
# file = Tempfile.new(['hello', '.jpg'])
-
# file.path # => something like: "/tmp/hello2843-8392-92849382--0.jpg"
-
#
-
# The temporary file will be placed in the directory as specified
-
# by the +tmpdir+ parameter. By default, this is +Dir.tmpdir+.
-
# When $SAFE > 0 and the given +tmpdir+ is tainted, it uses
-
# '/tmp' as the temporary directory. Please note that ENV values
-
# are tainted by default, and +Dir.tmpdir+'s return value might
-
# come from environment variables (e.g. <tt>$TMPDIR</tt>).
-
#
-
# file = Tempfile.new('hello', '/home/aisaka')
-
# file.path # => something like: "/home/aisaka/hello2843-8392-92849382--0"
-
#
-
# You can also pass an options hash. Under the hood, Tempfile creates
-
# the temporary file using +File.open+. These options will be passed to
-
# +File.open+. This is mostly useful for specifying encoding
-
# options, e.g.:
-
#
-
# Tempfile.new('hello', '/home/aisaka', :encoding => 'ascii-8bit')
-
#
-
# # You can also omit the 'tmpdir' parameter:
-
# Tempfile.new('hello', :encoding => 'ascii-8bit')
-
#
-
# === Exceptions
-
#
-
# If Tempfile.new cannot find a unique filename within a limited
-
# number of tries, then it will raise an exception.
-
1
def initialize(basename, *rest)
-
4
@data = []
-
4
@clean_proc = Remover.new(@data)
-
4
ObjectSpace.define_finalizer(self, @clean_proc)
-
-
4
create(basename, *rest) do |tmpname, n, opts|
-
4
mode = File::RDWR|File::CREAT|File::EXCL
-
4
perm = 0600
-
4
if opts
-
mode |= opts.delete(:mode) || 0
-
opts[:perm] = perm
-
perm = nil
-
else
-
4
opts = perm
-
end
-
4
self.class.locking(tmpname) do
-
4
@data[1] = @tmpfile = File.open(tmpname, mode, opts)
-
4
@data[0] = @tmpname = tmpname
-
end
-
4
@mode = mode & ~(File::CREAT|File::EXCL)
-
4
perm or opts.freeze
-
4
@opts = opts
-
end
-
-
4
super(@tmpfile)
-
end
-
-
# Opens or reopens the file with mode "r+".
-
1
def open
-
@tmpfile.close if @tmpfile
-
@tmpfile = File.open(@tmpname, @mode, @opts)
-
@data[1] = @tmpfile
-
__setobj__(@tmpfile)
-
end
-
-
1
def _close # :nodoc:
-
7
@tmpfile.close if @tmpfile
-
7
@tmpfile = nil
-
7
@data[1] = nil if @data
-
end
-
1
protected :_close
-
-
# Closes the file. If +unlink_now+ is true, then the file will be unlinked
-
# (deleted) after closing. Of course, you can choose to later call #unlink
-
# if you do not unlink it now.
-
#
-
# If you don't explicitly unlink the temporary file, the removal
-
# will be delayed until the object is finalized.
-
1
def close(unlink_now=false)
-
7
if unlink_now
-
3
close!
-
else
-
4
_close
-
end
-
end
-
-
# Closes and unlinks (deletes) the file. Has the same effect as called
-
# <tt>close(true)</tt>.
-
1
def close!
-
3
_close
-
3
unlink
-
3
ObjectSpace.undefine_finalizer(self)
-
end
-
-
# Unlinks (deletes) the file from the filesystem. One should always unlink
-
# the file after using it, as is explained in the "Explicit close" good
-
# practice section in the Tempfile overview:
-
#
-
# file = Tempfile.new('foo')
-
# begin
-
# ...do something with file...
-
# ensure
-
# file.close
-
# file.unlink # deletes the temp file
-
# end
-
#
-
# === Unlink-before-close
-
#
-
# On POSIX systems it's possible to unlink a file before closing it. This
-
# practice is explained in detail in the Tempfile overview (section
-
# "Unlink after creation"); please refer there for more information.
-
#
-
# However, unlink-before-close may not be supported on non-POSIX operating
-
# systems. Microsoft Windows is the most notable case: unlinking a non-closed
-
# file will result in an error, which this method will silently ignore. If
-
# you want to practice unlink-before-close whenever possible, then you should
-
# write code like this:
-
#
-
# file = Tempfile.new('foo')
-
# file.unlink # On Windows this silently fails.
-
# begin
-
# ... do something with file ...
-
# ensure
-
# file.close! # Closes the file handle. If the file wasn't unlinked
-
# # because #unlink failed, then this method will attempt
-
# # to do so again.
-
# end
-
1
def unlink
-
# keep this order for thread safeness
-
4
return unless @tmpname
-
4
begin
-
4
if File.exist?(@tmpname)
-
4
File.unlink(@tmpname)
-
end
-
# remove tmpname from remover
-
4
@data[0] = @data[2] = nil
-
4
@tmpname = nil
-
rescue Errno::EACCES
-
# may not be able to unlink on Windows; just ignore
-
end
-
end
-
1
alias delete unlink
-
-
# Returns the full path name of the temporary file.
-
# This will be nil if #unlink has been called.
-
1
def path
-
5
@tmpname
-
end
-
-
# Returns the size of the temporary file. As a side effect, the IO
-
# buffer is flushed before determining the size.
-
1
def size
-
if @tmpfile
-
@tmpfile.flush
-
@tmpfile.stat.size
-
elsif @tmpname
-
File.size(@tmpname)
-
else
-
0
-
end
-
end
-
1
alias length size
-
-
# :stopdoc:
-
1
class Remover
-
1
def initialize(data)
-
4
@pid = $$
-
4
@data = data
-
end
-
-
1
def call(*args)
-
if @pid == $$
-
path, tmpfile = *@data
-
-
STDERR.print "removing ", path, "..." if $DEBUG
-
-
tmpfile.close if tmpfile
-
-
# keep this order for thread safeness
-
if path
-
File.unlink(path) if File.exist?(path)
-
end
-
-
STDERR.print "done\n" if $DEBUG
-
end
-
end
-
end
-
# :startdoc:
-
-
1
class << self
-
# Creates a new Tempfile.
-
#
-
# If no block is given, this is a synonym for Tempfile.new.
-
#
-
# If a block is given, then a Tempfile object will be constructed,
-
# and the block is run with said object as argument. The Tempfile
-
# oject will be automatically closed after the block terminates.
-
# The call returns the value of the block.
-
#
-
# In any case, all arguments (+*args+) will be passed to Tempfile.new.
-
#
-
# Tempfile.open('foo', '/home/temp') do |f|
-
# ... do something with f ...
-
# end
-
#
-
# # Equivalent:
-
# f = Tempfile.open('foo', '/home/temp')
-
# begin
-
# ... do something with f ...
-
# ensure
-
# f.close
-
# end
-
1
def open(*args)
-
tempfile = new(*args)
-
-
if block_given?
-
begin
-
yield(tempfile)
-
ensure
-
tempfile.close
-
end
-
else
-
tempfile
-
end
-
end
-
-
# :stopdoc:
-
-
# yields with locking for +tmpname+ and returns the result of the
-
# block.
-
1
def locking(tmpname)
-
4
lock = tmpname + '.lock'
-
4
mkdir(lock)
-
4
yield
-
ensure
-
4
rmdir(lock) if lock
-
end
-
-
1
def mkdir(*args)
-
4
Dir.mkdir(*args)
-
end
-
-
1
def rmdir(*args)
-
4
Dir.rmdir(*args)
-
end
-
end
-
end
-
-
1
if __FILE__ == $0
-
# $DEBUG = true
-
f = Tempfile.new("foo")
-
f.print("foo\n")
-
f.close
-
f.open
-
p f.gets # => "foo\n"
-
f.close!
-
end
-
# Timeout long-running blocks
-
#
-
# == Synopsis
-
#
-
# require 'timeout'
-
# status = Timeout::timeout(5) {
-
# # Something that should be interrupted if it takes more than 5 seconds...
-
# }
-
#
-
# == Description
-
#
-
# Timeout provides a way to auto-terminate a potentially long-running
-
# operation if it hasn't finished in a fixed amount of time.
-
#
-
# Previous versions didn't use a module for namespacing, however
-
# #timeout is provided for backwards compatibility. You
-
# should prefer Timeout#timeout instead.
-
#
-
# == Copyright
-
#
-
# Copyright:: (C) 2000 Network Applied Communication Laboratory, Inc.
-
# Copyright:: (C) 2000 Information-technology Promotion Agency, Japan
-
-
1
module Timeout
-
# Raised by Timeout#timeout when the block times out.
-
1
class Error < RuntimeError
-
end
-
1
class ExitException < ::Exception # :nodoc:
-
end
-
-
# :stopdoc:
-
1
THIS_FILE = /\A#{Regexp.quote(__FILE__)}:/o
-
1
CALLER_OFFSET = ((c = caller[0]) && THIS_FILE =~ c) ? 1 : 0
-
# :startdoc:
-
-
# Perform an operation in a block, timing it out if it takes longer
-
# than +sec+ seconds to complete.
-
#
-
# +sec+:: Number of seconds to wait for the block to terminate. Any number
-
# may be used, including Floats to specify fractional seconds.
-
# +klass+:: Exception Class to raise if the block fails to terminate
-
# in +sec+ seconds. Omitting will use the default, Timeout::Error
-
#
-
# The block will be executed on another thread and will be given one
-
# argument: +sec+.
-
#
-
# Returns the result of the block *if* the block completed before
-
# +sec+ seconds, otherwise throws an exception, based on the value of +klass+.
-
#
-
# Note that this is both a method of module Timeout, so you can <tt>include
-
# Timeout</tt> into your classes so they have a #timeout method, as well as
-
# a module method, so you can call it directly as Timeout.timeout().
-
1
def timeout(sec, klass = nil) #:yield: +sec+
-
return yield(sec) if sec == nil or sec.zero?
-
exception = klass || Class.new(ExitException)
-
begin
-
begin
-
x = Thread.current
-
y = Thread.start {
-
begin
-
sleep sec
-
rescue => e
-
x.raise e
-
else
-
x.raise exception, "execution expired"
-
end
-
}
-
return yield(sec)
-
ensure
-
if y
-
y.kill
-
y.join # make sure y is dead.
-
end
-
end
-
rescue exception => e
-
rej = /\A#{Regexp.quote(__FILE__)}:#{__LINE__-4}\z/o
-
(bt = e.backtrace).reject! {|m| rej =~ m}
-
level = -caller(CALLER_OFFSET).size
-
while THIS_FILE =~ bt[level]
-
bt.delete_at(level)
-
level += 1
-
end
-
raise if klass # if exception class is specified, it
-
# would be expected outside.
-
raise Error, e.message, e.backtrace
-
end
-
end
-
-
1
module_function :timeout
-
end
-
-
# Identical to:
-
#
-
# Timeout::timeout(n, e, &block).
-
#
-
# This method is deprecated and provided only for backwards compatibility.
-
# You should use Timeout#timeout instead.
-
1
def timeout(n, e = nil, &block)
-
Timeout::timeout(n, e, &block)
-
end
-
-
# Another name for Timeout::Error, defined for backwards compatibility with
-
# earlier versions of timeout.rb.
-
1
TimeoutError = Timeout::Error
-
#
-
# tmpdir - retrieve temporary directory path
-
#
-
# $Id: tmpdir.rb 31635 2011-05-18 21:19:18Z drbrain $
-
#
-
-
1
require 'fileutils'
-
1
begin
-
1
require 'etc.so'
-
rescue LoadError
-
end
-
-
1
class Dir
-
-
1
@@systmpdir ||= defined?(Etc.systmpdir) ? Etc.systmpdir : '/tmp'
-
-
##
-
# Returns the operating system's temporary file path.
-
-
1
def Dir::tmpdir
-
4
tmp = '.'
-
4
if $SAFE > 0
-
tmp = @@systmpdir
-
else
-
4
for dir in [ENV['TMPDIR'], ENV['TMP'], ENV['TEMP'], @@systmpdir, '/tmp']
-
if dir and stat = File.stat(dir) and stat.directory? and stat.writable?
-
4
tmp = dir
-
4
break
-
16
end rescue nil
-
end
-
4
File.expand_path(tmp)
-
end
-
end
-
-
# Dir.mktmpdir creates a temporary directory.
-
#
-
# The directory is created with 0700 permission.
-
#
-
# The prefix and suffix of the name of the directory is specified by
-
# the optional first argument, <i>prefix_suffix</i>.
-
# - If it is not specified or nil, "d" is used as the prefix and no suffix is used.
-
# - If it is a string, it is used as the prefix and no suffix is used.
-
# - If it is an array, first element is used as the prefix and second element is used as a suffix.
-
#
-
# Dir.mktmpdir {|dir| dir is ".../d..." }
-
# Dir.mktmpdir("foo") {|dir| dir is ".../foo..." }
-
# Dir.mktmpdir(["foo", "bar"]) {|dir| dir is ".../foo...bar" }
-
#
-
# The directory is created under Dir.tmpdir or
-
# the optional second argument <i>tmpdir</i> if non-nil value is given.
-
#
-
# Dir.mktmpdir {|dir| dir is "#{Dir.tmpdir}/d..." }
-
# Dir.mktmpdir(nil, "/var/tmp") {|dir| dir is "/var/tmp/d..." }
-
#
-
# If a block is given,
-
# it is yielded with the path of the directory.
-
# The directory and its contents are removed
-
# using FileUtils.remove_entry_secure before Dir.mktmpdir returns.
-
# The value of the block is returned.
-
#
-
# Dir.mktmpdir {|dir|
-
# # use the directory...
-
# open("#{dir}/foo", "w") { ... }
-
# }
-
#
-
# If a block is not given,
-
# The path of the directory is returned.
-
# In this case, Dir.mktmpdir doesn't remove the directory.
-
#
-
# dir = Dir.mktmpdir
-
# begin
-
# # use the directory...
-
# open("#{dir}/foo", "w") { ... }
-
# ensure
-
# # remove the directory.
-
# FileUtils.remove_entry_secure dir
-
# end
-
#
-
1
def Dir.mktmpdir(prefix_suffix=nil, *rest)
-
path = Tmpname.create(prefix_suffix || "d", *rest) {|n| mkdir(n, 0700)}
-
if block_given?
-
begin
-
yield path
-
ensure
-
FileUtils.remove_entry_secure path
-
end
-
else
-
path
-
end
-
end
-
-
1
module Tmpname # :nodoc:
-
1
module_function
-
-
1
def tmpdir
-
4
Dir.tmpdir
-
end
-
-
1
def make_tmpname(prefix_suffix, n)
-
4
case prefix_suffix
-
when String
-
prefix = prefix_suffix
-
suffix = ""
-
when Array
-
4
prefix = prefix_suffix[0]
-
4
suffix = prefix_suffix[1]
-
else
-
raise ArgumentError, "unexpected prefix_suffix: #{prefix_suffix.inspect}"
-
end
-
4
t = Time.now.strftime("%Y%m%d")
-
4
path = "#{prefix}#{t}-#{$$}-#{rand(0x100000000).to_s(36)}"
-
4
path << "-#{n}" if n
-
4
path << suffix
-
end
-
-
1
def create(basename, *rest)
-
4
if opts = Hash.try_convert(rest[-1])
-
opts = opts.dup if rest.pop.equal?(opts)
-
max_try = opts.delete(:max_try)
-
opts = [opts]
-
else
-
4
opts = []
-
end
-
4
tmpdir, = *rest
-
4
if $SAFE > 0 and tmpdir.tainted?
-
tmpdir = '/tmp'
-
else
-
4
tmpdir ||= tmpdir()
-
end
-
4
n = nil
-
4
begin
-
4
path = File.expand_path(make_tmpname(basename, n), tmpdir)
-
4
yield(path, n, *opts)
-
rescue Errno::EEXIST
-
n ||= 0
-
n += 1
-
retry if !max_try or n < max_try
-
raise "cannot generate temporary name using `#{basename}' under `#{tmpdir}'"
-
end
-
4
path
-
end
-
end
-
end
-
#--
-
# Copyright (c) 2004-2012 David Heinemeier Hansson
-
#
-
# Permission is hereby granted, free of charge, to any person obtaining
-
# a copy of this software and associated documentation files (the
-
# "Software"), to deal in the Software without restriction, including
-
# without limitation the rights to use, copy, modify, merge, publish,
-
# distribute, sublicense, and/or sell copies of the Software, and to
-
# permit persons to whom the Software is furnished to do so, subject to
-
# the following conditions:
-
#
-
# The above copyright notice and this permission notice shall be
-
# included in all copies or substantial portions of the Software.
-
#
-
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
-
# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
-
# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
-
# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
-
# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
-
# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
-
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
-
#++
-
-
1
require 'active_support'
-
1
require 'active_support/rails'
-
1
require 'active_model/version'
-
-
1
module ActiveModel
-
1
extend ActiveSupport::Autoload
-
-
1
autoload :AttributeMethods
-
1
autoload :BlockValidator, 'active_model/validator'
-
1
autoload :Callbacks
-
1
autoload :Conversion
-
1
autoload :Dirty
-
1
autoload :EachValidator, 'active_model/validator'
-
1
autoload :ForbiddenAttributesProtection
-
1
autoload :Lint
-
1
autoload :Model
-
1
autoload :DeprecatedMassAssignmentSecurity
-
1
autoload :Name, 'active_model/naming'
-
1
autoload :Naming
-
1
autoload :Observer, 'active_model/observing'
-
1
autoload :Observing
-
1
autoload :SecurePassword
-
1
autoload :Serialization
-
1
autoload :TestCase
-
1
autoload :Translation
-
1
autoload :Validations
-
1
autoload :Validator
-
-
1
eager_autoload do
-
1
autoload :Errors
-
end
-
-
1
module Serializers
-
1
extend ActiveSupport::Autoload
-
-
1
eager_autoload do
-
1
autoload :JSON
-
1
autoload :Xml
-
end
-
end
-
-
1
def eager_load!
-
super
-
ActiveModel::Serializer.eager_load!
-
end
-
end
-
-
1
ActiveSupport.on_load(:i18n) do
-
1
I18n.load_path << File.dirname(__FILE__) + '/active_model/locale/en.yml'
-
end
-
-
1
module ActiveModel
-
# Raised when an attribute is not defined.
-
#
-
# class User < ActiveRecord::Base
-
# has_many :pets
-
# end
-
#
-
# user = User.first
-
# user.pets.select(:id).first.user_id
-
# # => ActiveModel::MissingAttributeError: missing attribute: user_id
-
1
class MissingAttributeError < NoMethodError
-
end
-
# == Active \Model Attribute Methods
-
#
-
# <tt>ActiveModel::AttributeMethods</tt> provides a way to add prefixes and
-
# suffixes to your methods as well as handling the creation of Active Record
-
# like class methods such as +table_name+.
-
#
-
# The requirements to implement ActiveModel::AttributeMethods are to:
-
#
-
# * <tt>include ActiveModel::AttributeMethods</tt> in your object.
-
# * Call each Attribute Method module method you want to add, such as
-
# +attribute_method_suffix+ or +attribute_method_prefix+.
-
# * Call +define_attribute_methods+ after the other methods are called.
-
# * Define the various generic +_attribute+ methods that you have declared.
-
#
-
# A minimal implementation could be:
-
#
-
# class Person
-
# include ActiveModel::AttributeMethods
-
#
-
# attribute_method_affix prefix: 'reset_', suffix: '_to_default!'
-
# attribute_method_suffix '_contrived?'
-
# attribute_method_prefix 'clear_'
-
# define_attribute_methods :name
-
#
-
# attr_accessor :name
-
#
-
# private
-
#
-
# def attribute_contrived?(attr)
-
# true
-
# end
-
#
-
# def clear_attribute(attr)
-
# send("#{attr}=", nil)
-
# end
-
#
-
# def reset_attribute_to_default!(attr)
-
# send("#{attr}=", 'Default Name')
-
# end
-
# end
-
#
-
# Note that whenever you include ActiveModel::AttributeMethods in your class,
-
# it requires you to implement an +attributes+ method which returns a hash
-
# with each attribute name in your model as hash key and the attribute value as
-
# hash value.
-
#
-
# Hash keys must be strings.
-
1
module AttributeMethods
-
1
extend ActiveSupport::Concern
-
-
1
NAME_COMPILABLE_REGEXP = /\A[a-zA-Z_]\w*[!?=]?\z/
-
1
CALL_COMPILABLE_REGEXP = /\A[a-zA-Z_]\w*[!?]?\z/
-
-
1
included do
-
3
class_attribute :attribute_aliases, :attribute_method_matchers, instance_writer: false
-
3
self.attribute_aliases = {}
-
3
self.attribute_method_matchers = [ClassMethods::AttributeMethodMatcher.new]
-
end
-
-
1
module ClassMethods
-
# Declares a method available for all attributes with the given prefix.
-
# Uses +method_missing+ and <tt>respond_to?</tt> to rewrite the method.
-
#
-
# #{prefix}#{attr}(*args, &block)
-
#
-
# to
-
#
-
# #{prefix}attribute(#{attr}, *args, &block)
-
#
-
# An instance method <tt>#{prefix}attribute</tt> must exist and accept
-
# at least the +attr+ argument.
-
#
-
# class Person
-
# include ActiveModel::AttributeMethods
-
#
-
# attr_accessor :name
-
# attribute_method_prefix 'clear_'
-
# define_attribute_methods :name
-
#
-
# private
-
#
-
# def clear_attribute(attr)
-
# send("#{attr}=", nil)
-
# end
-
# end
-
#
-
# person = Person.new
-
# person.name = 'Bob'
-
# person.name # => "Bob"
-
# person.clear_name
-
# person.name # => nil
-
1
def attribute_method_prefix(*prefixes)
-
4
self.attribute_method_matchers += prefixes.map! { |prefix| AttributeMethodMatcher.new prefix: prefix }
-
2
undefine_attribute_methods
-
end
-
-
# Declares a method available for all attributes with the given suffix.
-
# Uses +method_missing+ and <tt>respond_to?</tt> to rewrite the method.
-
#
-
# #{attr}#{suffix}(*args, &block)
-
#
-
# to
-
#
-
# attribute#{suffix}(#{attr}, *args, &block)
-
#
-
# An <tt>attribute#{suffix}</tt> instance method must exist and accept at
-
# least the +attr+ argument.
-
#
-
# class Person
-
# include ActiveModel::AttributeMethods
-
#
-
# attr_accessor :name
-
# attribute_method_suffix '_short?'
-
# define_attribute_methods :name
-
#
-
# private
-
#
-
# def attribute_short?(attr)
-
# send(attr).length < 5
-
# end
-
# end
-
#
-
# person = Person.new
-
# person.name = 'Bob'
-
# person.name # => "Bob"
-
# person.name_short? # => true
-
1
def attribute_method_suffix(*suffixes)
-
43
self.attribute_method_matchers += suffixes.map! { |suffix| AttributeMethodMatcher.new suffix: suffix }
-
17
undefine_attribute_methods
-
end
-
-
# Declares a method available for all attributes with the given prefix
-
# and suffix. Uses +method_missing+ and <tt>respond_to?</tt> to rewrite
-
# the method.
-
#
-
# #{prefix}#{attr}#{suffix}(*args, &block)
-
#
-
# to
-
#
-
# #{prefix}attribute#{suffix}(#{attr}, *args, &block)
-
#
-
# An <tt>#{prefix}attribute#{suffix}</tt> instance method must exist and
-
# accept at least the +attr+ argument.
-
#
-
# class Person
-
# include ActiveModel::AttributeMethods
-
#
-
# attr_accessor :name
-
# attribute_method_affix prefix: 'reset_', suffix: '_to_default!'
-
# define_attribute_methods :name
-
#
-
# private
-
#
-
# def reset_attribute_to_default!(attr)
-
# ...
-
# end
-
# end
-
#
-
# person = Person.new
-
# person.name # => 'Gem'
-
# person.reset_name_to_default!
-
# person.name # => 'Gemma'
-
1
def attribute_method_affix(*affixes)
-
12
self.attribute_method_matchers += affixes.map! { |affix| AttributeMethodMatcher.new prefix: affix[:prefix], suffix: affix[:suffix] }
-
6
undefine_attribute_methods
-
end
-
-
-
# Allows you to make aliases for attributes.
-
#
-
# class Person
-
# include ActiveModel::AttributeMethods
-
#
-
# attr_accessor :name
-
# attribute_method_suffix '_short?'
-
# define_attribute_methods :name
-
#
-
# alias_attribute :nickname, :name
-
#
-
# private
-
#
-
# def attribute_short?(attr)
-
# send(attr).length < 5
-
# end
-
# end
-
#
-
# person = Person.new
-
# person.name = 'Bob'
-
# person.name # => "Bob"
-
# person.nickname # => "Bob"
-
# person.name_short? # => true
-
# person.nickname_short? # => true
-
1
def alias_attribute(new_name, old_name)
-
2
self.attribute_aliases = attribute_aliases.merge(new_name.to_s => old_name.to_s)
-
2
attribute_method_matchers.each do |matcher|
-
18
matcher_new = matcher.method_name(new_name).to_s
-
18
matcher_old = matcher.method_name(old_name).to_s
-
18
define_proxy_call false, self, matcher_new, matcher_old
-
end
-
end
-
-
# Declares the attributes that should be prefixed and suffixed by
-
# ActiveModel::AttributeMethods.
-
#
-
# To use, pass attribute names (as strings or symbols), be sure to declare
-
# +define_attribute_methods+ after you define any prefix, suffix or affix
-
# methods, or they will not hook in.
-
#
-
# class Person
-
# include ActiveModel::AttributeMethods
-
#
-
# attr_accessor :name, :age, :address
-
# attribute_method_prefix 'clear_'
-
#
-
# # Call to define_attribute_methods must appear after the
-
# # attribute_method_prefix, attribute_method_suffix or
-
# # attribute_method_affix declares.
-
# define_attribute_methods :name, :age, :address
-
#
-
# private
-
#
-
# def clear_attribute(attr)
-
# ...
-
# end
-
# end
-
1
def define_attribute_methods(*attr_names)
-
2808
attr_names.flatten.each { |attr_name| define_attribute_method(attr_name) }
-
end
-
-
# Declares an attribute that should be prefixed and suffixed by
-
# ActiveModel::AttributeMethods.
-
#
-
# To use, pass an attribute name (as string or symbol), be sure to declare
-
# +define_attribute_method+ after you define any prefix, suffix or affix
-
# method, or they will not hook in.
-
#
-
# class Person
-
# include ActiveModel::AttributeMethods
-
#
-
# attr_accessor :name
-
# attribute_method_suffix '_short?'
-
#
-
# # Call to define_attribute_method must appear after the
-
# # attribute_method_prefix, attribute_method_suffix or
-
# # attribute_method_affix declares.
-
# define_attribute_method :name
-
#
-
# private
-
#
-
# def attribute_short?(attr)
-
# send(attr).length < 5
-
# end
-
# end
-
#
-
# person = Person.new
-
# person.name = 'Bob'
-
# person.name # => "Bob"
-
# person.name_short? # => true
-
1
def define_attribute_method(attr_name)
-
2457
attribute_method_matchers.each do |matcher|
-
22521
method_name = matcher.method_name(attr_name)
-
-
22521
unless instance_method_already_implemented?(method_name)
-
22458
generate_method = "define_method_#{matcher.method_missing_target}"
-
-
22458
if respond_to?(generate_method, true)
-
4894
send(generate_method, attr_name)
-
else
-
17564
define_proxy_call true, generated_attribute_methods, method_name, matcher.method_missing_target, attr_name.to_s
-
end
-
end
-
end
-
2457
attribute_method_matchers_cache.clear
-
end
-
-
# Removes all the previously dynamically defined methods from the class.
-
#
-
# class Person
-
# include ActiveModel::AttributeMethods
-
#
-
# attr_accessor :name
-
# attribute_method_suffix '_short?'
-
# define_attribute_method :name
-
#
-
# private
-
#
-
# def attribute_short?(attr)
-
# send(attr).length < 5
-
# end
-
# end
-
#
-
# person = Person.new
-
# person.name = 'Bob'
-
# person.name_short? # => true
-
#
-
# Person.undefine_attribute_methods
-
#
-
# person.name_short? # => NoMethodError
-
1
def undefine_attribute_methods
-
56
generated_attribute_methods.module_eval do
-
4452
instance_methods.each { |m| undef_method(m) }
-
end
-
56
attribute_method_matchers_cache.clear
-
end
-
-
# Returns true if the attribute methods defined have been generated.
-
1
def generated_attribute_methods #:nodoc:
-
51770
@generated_attribute_methods ||= Module.new.tap { |mod| include mod }
-
end
-
-
1
protected
-
1
def instance_method_already_implemented?(method_name) #:nodoc:
-
22502
generated_attribute_methods.method_defined?(method_name)
-
end
-
-
1
private
-
# The methods +method_missing+ and +respond_to?+ of this module are
-
# invoked often in a typical rails, both of which invoke the method
-
# +match_attribute_method?+. The latter method iterates through an
-
# array doing regular expression matches, which results in a lot of
-
# object creations. Most of the times it returns a +nil+ match. As the
-
# match result is always the same given a +method_name+, this cache is
-
# used to alleviate the GC, which ultimately also speeds up the app
-
# significantly (in our case our test suite finishes 10% faster with
-
# this cache).
-
1
def attribute_method_matchers_cache #:nodoc:
-
13556
@attribute_method_matchers_cache ||= {}
-
end
-
-
1
def attribute_method_matcher(method_name) #:nodoc:
-
8795
attribute_method_matchers_cache.fetch(method_name) do |name|
-
# Must try to match prefixes/suffixes first, or else the matcher with no prefix/suffix
-
# will match every time.
-
2248
matchers = attribute_method_matchers.partition(&:plain?).reverse.flatten(1)
-
2248
match = nil
-
22356
matchers.detect { |method| match = method.match(name) }
-
2248
attribute_method_matchers_cache[name] = match
-
end
-
end
-
-
# Define a method `name` in `mod` that dispatches to `send`
-
# using the given `extra` args. This fallbacks `define_method`
-
# and `send` if the given names cannot be compiled.
-
1
def define_proxy_call(include_private, mod, name, send, *extra) #:nodoc:
-
17582
defn = if name =~ NAME_COMPILABLE_REGEXP
-
17575
"def #{name}(*args)"
-
else
-
7
"define_method(:'#{name}') do |*args|"
-
end
-
-
17582
extra = (extra.map!(&:inspect) << "*args").join(", ")
-
-
17582
target = if send =~ CALL_COMPILABLE_REGEXP
-
17546
"#{"self." unless include_private}#{send}(#{extra})"
-
else
-
36
"send(:'#{send}', #{extra})"
-
end
-
-
17582
mod.module_eval <<-RUBY, __FILE__, __LINE__ + 1
-
#{defn}
-
#{target}
-
end
-
RUBY
-
end
-
-
1
class AttributeMethodMatcher #:nodoc:
-
1
attr_reader :prefix, :suffix, :method_missing_target
-
-
1
AttributeMethodMatch = Struct.new(:target, :attr_name, :method_name)
-
-
1
def initialize(options = {})
-
37
if options[:prefix] == '' || options[:suffix] == ''
-
message = "Specifying an empty prefix/suffix for an attribute method is no longer " \
-
"necessary. If the un-prefixed/suffixed version of the method has not been " \
-
"defined when `define_attribute_methods` is called, it will be defined " \
-
"automatically."
-
ActiveSupport::Deprecation.warn message
-
end
-
-
37
@prefix, @suffix = options.fetch(:prefix, ''), options.fetch(:suffix, '')
-
37
@regex = /^(?:#{Regexp.escape(@prefix)})(.*)(?:#{Regexp.escape(@suffix)})$/
-
37
@method_missing_target = "#{@prefix}attribute#{@suffix}"
-
37
@method_name = "#{prefix}%s#{suffix}"
-
end
-
-
1
def match(method_name)
-
20108
if @regex =~ method_name
-
2248
AttributeMethodMatch.new(method_missing_target, $1, method_name)
-
end
-
end
-
-
1
def method_name(attr_name)
-
22557
@method_name % attr_name
-
end
-
-
1
def plain?
-
20232
prefix.empty? && suffix.empty?
-
end
-
end
-
end
-
-
# Allows access to the object attributes, which are held in the
-
# <tt>@attributes</tt> hash, as though they were first-class methods. So a
-
# Person class with a name attribute can use Person#name and Person#name=
-
# and never directly use the attributes hash -- except for multiple assigns
-
# with ActiveRecord#attributes=. A Milestone class can also ask
-
# Milestone#completed? to test that the completed attribute is not +nil+
-
# or 0.
-
#
-
# It's also possible to instantiate related objects, so a Client class
-
# belonging to the clients table with a +master_id+ foreign key can
-
# instantiate master through Client#master.
-
1
def method_missing(method, *args, &block)
-
55
if respond_to_without_attributes?(method, true)
-
11
super
-
else
-
44
match = match_attribute_method?(method.to_s)
-
44
match ? attribute_missing(match, *args, &block) : super
-
end
-
end
-
-
# attribute_missing is like method_missing, but for attributes. When method_missing is
-
# called we check to see if there is a matching attribute method. If so, we call
-
# attribute_missing to dispatch the attribute. This method can be overloaded to
-
# customise the behaviour.
-
1
def attribute_missing(match, *args, &block)
-
21
__send__(match.target, match.attr_name, *args, &block)
-
end
-
-
# A Person object with a name attribute can ask <tt>person.respond_to?(:name)</tt>,
-
# <tt>person.respond_to?(:name=)</tt>, and <tt>person.respond_to?(:name?)</tt>
-
# which will all return +true+.
-
1
alias :respond_to_without_attributes? :respond_to?
-
1
def respond_to?(method, include_private_methods = false)
-
48676
if super
-
39866
true
-
8810
elsif !include_private_methods && super(method, true)
-
# If we're here then we haven't found among non-private methods
-
# but found among all methods. Which means that the given method is private.
-
59
false
-
else
-
8751
!match_attribute_method?(method.to_s).nil?
-
end
-
end
-
-
1
protected
-
1
def attribute_method?(attr_name) #:nodoc:
-
respond_to_without_attributes?(:attributes) && attributes.include?(attr_name)
-
end
-
-
1
private
-
# Returns a struct representing the matching attribute method.
-
# The struct's attributes are prefix, base and suffix.
-
1
def match_attribute_method?(method_name)
-
8795
match = self.class.send(:attribute_method_matcher, method_name)
-
8795
match if match && attribute_method?(match.attr_name)
-
end
-
-
1
def missing_attribute(attr_name, stack)
-
4
raise ActiveModel::MissingAttributeError, "missing attribute: #{attr_name}", stack
-
end
-
end
-
end
-
1
require 'active_support/callbacks'
-
-
1
module ActiveModel
-
# == Active \Model \Callbacks
-
#
-
# Provides an interface for any class to have Active Record like callbacks.
-
#
-
# Like the Active Record methods, the callback chain is aborted as soon as
-
# one of the methods in the chain returns +false+.
-
#
-
# First, extend ActiveModel::Callbacks from the class you are creating:
-
#
-
# class MyModel
-
# extend ActiveModel::Callbacks
-
# end
-
#
-
# Then define a list of methods that you want callbacks attached to:
-
#
-
# define_model_callbacks :create, :update
-
#
-
# This will provide all three standard callbacks (before, around and after)
-
# for both the <tt>:create</tt> and <tt>:update</tt> methods. To implement,
-
# you need to wrap the methods you want callbacks on in a block so that the
-
# callbacks get a chance to fire:
-
#
-
# def create
-
# run_callbacks :create do
-
# # Your create action methods here
-
# end
-
# end
-
#
-
# Then in your class, you can use the +before_create+, +after_create+ and
-
# +around_create+ methods, just as you would in an Active Record module.
-
#
-
# before_create :action_before_create
-
#
-
# def action_before_create
-
# # Your code here
-
# end
-
#
-
# When defining an around callback remember to yield to the block, otherwise
-
# it won't be executed:
-
#
-
# around_create :log_status
-
#
-
# def log_status
-
# puts 'going to call the block...'
-
# yield
-
# puts 'block successfully called.'
-
# end
-
#
-
# You can choose not to have all three callbacks by passing a hash to the
-
# +define_model_callbacks+ method.
-
#
-
# define_model_callbacks :create, only: [:after, :before]
-
#
-
# Would only create the +after_create+ and +before_create+ callback methods in
-
# your class.
-
1
module Callbacks
-
1
def self.extended(base) #:nodoc:
-
1
base.class_eval do
-
1
include ActiveSupport::Callbacks
-
end
-
end
-
-
# define_model_callbacks accepts the same options +define_callbacks+ does,
-
# in case you want to overwrite a default. Besides that, it also accepts an
-
# <tt>:only</tt> option, where you can choose if you want all types (before,
-
# around or after) or just some.
-
#
-
# define_model_callbacks :initializer, only: :after
-
#
-
# Note, the <tt>only: <type></tt> hash will apply to all callbacks defined
-
# on that method call. To get around this you can call the define_model_callbacks
-
# method as many times as you need.
-
#
-
# define_model_callbacks :create, only: :after
-
# define_model_callbacks :update, only: :before
-
# define_model_callbacks :destroy, only: :around
-
#
-
# Would create +after_create+, +before_update+ and +around_destroy+ methods
-
# only.
-
#
-
# You can pass in a class to before_<type>, after_<type> and around_<type>,
-
# in which case the callback will call that class's <action>_<type> method
-
# passing the object that the callback is being called on.
-
#
-
# class MyModel
-
# extend ActiveModel::Callbacks
-
# define_model_callbacks :create
-
#
-
# before_create AnotherClass
-
# end
-
#
-
# class AnotherClass
-
# def self.before_create( obj )
-
# # obj is the MyModel instance that the callback is being called on
-
# end
-
# end
-
1
def define_model_callbacks(*callbacks)
-
2
options = callbacks.extract_options!
-
2
options = {
-
:terminator => "result == false",
-
:skip_after_callbacks_if_terminated => true,
-
:scope => [:kind, :name],
-
:only => [:before, :around, :after]
-
}.merge!(options)
-
-
2
types = Array(options.delete(:only))
-
-
2
callbacks.each do |callback|
-
7
define_callbacks(callback, options)
-
-
7
types.each do |type|
-
15
send("_define_#{type}_model_callback", self, callback)
-
end
-
end
-
end
-
-
1
private
-
-
1
def _define_before_model_callback(klass, callback) #:nodoc:
-
4
klass.class_eval <<-CALLBACK, __FILE__, __LINE__ + 1
-
def self.before_#{callback}(*args, &block)
-
set_callback(:#{callback}, :before, *args, &block)
-
end
-
CALLBACK
-
end
-
-
1
def _define_around_model_callback(klass, callback) #:nodoc:
-
4
klass.class_eval <<-CALLBACK, __FILE__, __LINE__ + 1
-
def self.around_#{callback}(*args, &block)
-
set_callback(:#{callback}, :around, *args, &block)
-
end
-
CALLBACK
-
end
-
-
1
def _define_after_model_callback(klass, callback) #:nodoc:
-
7
klass.class_eval <<-CALLBACK, __FILE__, __LINE__ + 1
-
def self.after_#{callback}(*args, &block)
-
options = args.extract_options!
-
options[:prepend] = true
-
options[:if] = Array(options[:if]) << "value != false"
-
set_callback(:#{callback}, :after, *(args << options), &block)
-
end
-
CALLBACK
-
end
-
end
-
end
-
1
require 'active_support/inflector'
-
-
1
module ActiveModel
-
# == Active \Model Conversions
-
#
-
# Handles default conversions: to_model, to_key, to_param, and to_partial_path.
-
#
-
# Let's take for example this non-persisted object.
-
#
-
# class ContactMessage
-
# include ActiveModel::Conversion
-
#
-
# # ContactMessage are never persisted in the DB
-
# def persisted?
-
# false
-
# end
-
# end
-
#
-
# cm = ContactMessage.new
-
# cm.to_model == cm # => true
-
# cm.to_key # => nil
-
# cm.to_param # => nil
-
# cm.to_partial_path # => "contact_messages/contact_message"
-
1
module Conversion
-
1
extend ActiveSupport::Concern
-
-
# If your object is already designed to implement all of the Active Model
-
# you can use the default <tt>:to_model</tt> implementation, which simply
-
# returns +self+.
-
#
-
# class Person
-
# include ActiveModel::Conversion
-
# end
-
#
-
# person = Person.new
-
# person.to_model == person # => true
-
#
-
# If your model does not act like an Active Model object, then you should
-
# define <tt>:to_model</tt> yourself returning a proxy object that wraps
-
# your object with Active Model compliant methods.
-
1
def to_model
-
15
self
-
end
-
-
# Returns an Enumerable of all key attributes if any is set, regardless if
-
# the object is persisted or not. If there no key attributes, returns +nil+.
-
#
-
# class Person < ActiveRecord::Base
-
# end
-
#
-
# person = Person.create
-
# person.to_key # => [1]
-
1
def to_key
-
key = respond_to?(:id) && id
-
key ? [key] : nil
-
end
-
-
# Returns a +string+ representing the object's key suitable for use in URLs,
-
# or +nil+ if <tt>persisted?</tt> is +false+.
-
#
-
# class Person < ActiveRecord::Base
-
# end
-
#
-
# person = Person.create
-
# person.to_param # => "1"
-
1
def to_param
-
persisted? ? to_key.join('-') : nil
-
end
-
-
# Returns a +string+ identifying the path associated with the object.
-
# ActionPack uses this to find a suitable partial to represent the object.
-
#
-
# class Person
-
# include ActiveModel::Conversion
-
# end
-
#
-
# person = Person.new
-
# person.to_partial_path # => "people/person"
-
1
def to_partial_path
-
1
self.class._to_partial_path
-
end
-
-
1
module ClassMethods #:nodoc:
-
# Provide a class level cache for #to_partial_path. This is an
-
# internal method and should not be accessed directly.
-
1
def _to_partial_path #:nodoc:
-
@_to_partial_path ||= begin
-
1
element = ActiveSupport::Inflector.underscore(ActiveSupport::Inflector.demodulize(self))
-
1
collection = ActiveSupport::Inflector.tableize(self)
-
1
"#{collection}/#{element}".freeze
-
1
end
-
end
-
end
-
end
-
end
-
1
module ActiveModel
-
1
module DeprecatedMassAssignmentSecurity # :nodoc:
-
1
extend ActiveSupport::Concern
-
-
1
module ClassMethods # :nodoc:
-
1
def attr_protected(*args)
-
raise "`attr_protected` is extracted out of Rails into a gem. " \
-
"Please use new recommended protection model for params " \
-
"or add `protected_attributes` to your Gemfile to use old one."
-
end
-
-
1
def attr_accessible(*args)
-
raise "`attr_accessible` is extracted out of Rails into a gem. " \
-
"Please use new recommended protection model for params " \
-
"or add `protected_attributes` to your Gemfile to use old one."
-
end
-
end
-
end
-
end
-
1
require 'active_model/attribute_methods'
-
1
require 'active_support/hash_with_indifferent_access'
-
1
require 'active_support/core_ext/object/duplicable'
-
-
1
module ActiveModel
-
# == Active \Model \Dirty
-
#
-
# Provides a way to track changes in your object in the same way as
-
# Active Record does.
-
#
-
# The requirements for implementing ActiveModel::Dirty are:
-
#
-
# * <tt>include ActiveModel::Dirty</tt> in your object.
-
# * Call <tt>define_attribute_methods</tt> passing each method you want to
-
# track.
-
# * Call <tt>attr_name_will_change!</tt> before each change to the tracked
-
# attribute.
-
#
-
# If you wish to also track previous changes on save or update, you need to
-
# add:
-
#
-
# @previously_changed = changes
-
#
-
# inside of your save or update method.
-
#
-
# A minimal implementation could be:
-
#
-
# class Person
-
# include ActiveModel::Dirty
-
#
-
# define_attribute_methods :name
-
#
-
# def name
-
# @name
-
# end
-
#
-
# def name=(val)
-
# name_will_change! unless val == @name
-
# @name = val
-
# end
-
#
-
# def save
-
# @previously_changed = changes
-
# @changed_attributes.clear
-
# end
-
# end
-
#
-
# A newly instantiated object is unchanged:
-
#
-
# person = Person.find_by_name('Uncle Bob')
-
# person.changed? # => false
-
#
-
# Change the name:
-
#
-
# person.name = 'Bob'
-
# person.changed? # => true
-
# person.name_changed? # => true
-
# person.name_was # => "Uncle Bob"
-
# person.name_change # => ["Uncle Bob", "Bob"]
-
# person.name = 'Bill'
-
# person.name_change # => ["Uncle Bob", "Bill"]
-
#
-
# Save the changes:
-
#
-
# person.save
-
# person.changed? # => false
-
# person.name_changed? # => false
-
#
-
# Assigning the same value leaves the attribute unchanged:
-
#
-
# person.name = 'Bill'
-
# person.name_changed? # => false
-
# person.name_change # => nil
-
#
-
# Which attributes have changed?
-
#
-
# person.name = 'Bob'
-
# person.changed # => ["name"]
-
# person.changes # => {"name" => ["Bill", "Bob"]}
-
#
-
# If an attribute is modified in-place then make use of <tt>[attribute_name]_will_change!</tt>
-
# to mark that the attribute is changing. Otherwise ActiveModel can't track
-
# changes to in-place attributes.
-
#
-
# person.name_will_change!
-
# person.name_change # => ["Bill", "Bill"]
-
# person.name << 'y'
-
# person.name_change # => ["Bill", "Billy"]
-
1
module Dirty
-
1
extend ActiveSupport::Concern
-
1
include ActiveModel::AttributeMethods
-
-
1
included do
-
3
attribute_method_suffix '_changed?', '_change', '_will_change!', '_was'
-
3
attribute_method_affix :prefix => 'reset_', :suffix => '!'
-
end
-
-
# Returns +true+ if any attribute have unsaved changes, +false+ otherwise.
-
#
-
# person.changed? # => false
-
# person.name = 'bob'
-
# person.changed? # => true
-
1
def changed?
-
1098
changed_attributes.present?
-
end
-
-
# Returns an array with the name of the attributes with unsaved changes.
-
#
-
# person.changed # => []
-
# person.name = 'bob'
-
# person.changed # => ["name"]
-
1
def changed
-
6889
changed_attributes.keys
-
end
-
-
# Returns a hash of changed attributes indicating their original
-
# and new values like <tt>attr => [original value, new value]</tt>.
-
#
-
# person.changes # => {}
-
# person.name = 'bob'
-
# person.changes # => { "name" => ["bill", "bob"] }
-
1
def changes
-
11618
HashWithIndifferentAccess[changed.map { |attr| [attr, attribute_change(attr)] }]
-
end
-
-
# Returns a hash of attributes that were changed before the model was saved.
-
#
-
# person.name # => "bob"
-
# person.name = 'robert'
-
# person.save
-
# person.previous_changes # => {"name" => ["bob", "robert"]}
-
1
def previous_changes
-
47
@previously_changed
-
end
-
-
# Returns a hash of the attributes with unsaved changes indicating their original
-
# values like <tt>attr => original value</tt>.
-
#
-
# person.name # => "bob"
-
# person.name = 'robert'
-
# person.changed_attributes # => {"name" => "bob"}
-
1
def changed_attributes
-
40111
@changed_attributes ||= {}
-
end
-
-
1
private
-
-
# Handle <tt>*_changed?</tt> for +method_missing+.
-
1
def attribute_changed?(attr)
-
23464
changed_attributes.include?(attr)
-
end
-
-
# Handle <tt>*_change</tt> for +method_missing+.
-
1
def attribute_change(attr)
-
8488
[changed_attributes[attr], __send__(attr)] if attribute_changed?(attr)
-
end
-
-
# Handle <tt>*_was</tt> for +method_missing+.
-
1
def attribute_was(attr)
-
11
attribute_changed?(attr) ? changed_attributes[attr] : __send__(attr)
-
end
-
-
# Handle <tt>*_will_change!</tt> for +method_missing+.
-
1
def attribute_will_change!(attr)
-
162
return if attribute_changed?(attr)
-
-
99
begin
-
99
value = __send__(attr)
-
99
value = value.duplicable? ? value.clone : value
-
rescue TypeError, NoMethodError
-
end
-
-
99
changed_attributes[attr] = value
-
end
-
-
# Handle <tt>reset_*!</tt> for +method_missing+.
-
1
def reset_attribute!(attr)
-
2
__send__("#{attr}=", changed_attributes[attr]) if attribute_changed?(attr)
-
end
-
end
-
end
-
# -*- coding: utf-8 -*-
-
-
1
require 'active_support/core_ext/array/conversions'
-
1
require 'active_support/core_ext/string/inflections'
-
-
1
module ActiveModel
-
# == Active \Model \Errors
-
#
-
# Provides a modified +Hash+ that you can include in your object
-
# for handling error messages and interacting with Action Pack helpers.
-
#
-
# A minimal implementation could be:
-
#
-
# class Person
-
#
-
# # Required dependency for ActiveModel::Errors
-
# extend ActiveModel::Naming
-
#
-
# def initialize
-
# @errors = ActiveModel::Errors.new(self)
-
# end
-
#
-
# attr_accessor :name
-
# attr_reader :errors
-
#
-
# def validate!
-
# errors.add(:name, "can not be nil") if name == nil
-
# end
-
#
-
# # The following methods are needed to be minimally implemented
-
#
-
# def read_attribute_for_validation(attr)
-
# send(attr)
-
# end
-
#
-
# def Person.human_attribute_name(attr, options = {})
-
# attr
-
# end
-
#
-
# def Person.lookup_ancestors
-
# [self]
-
# end
-
#
-
# end
-
#
-
# The last three methods are required in your object for Errors to be
-
# able to generate error messages correctly and also handle multiple
-
# languages. Of course, if you extend your object with ActiveModel::Translation
-
# you will not need to implement the last two. Likewise, using
-
# ActiveModel::Validations will handle the validation related methods
-
# for you.
-
#
-
# The above allows you to do:
-
#
-
# p = Person.new
-
# person.validate! # => ["can not be nil"]
-
# person.errors.full_messages # => ["name can not be nil"]
-
# # etc..
-
1
class Errors
-
1
include Enumerable
-
-
1
CALLBACKS_OPTIONS = [:if, :unless, :on, :allow_nil, :allow_blank, :strict]
-
-
1
attr_reader :messages
-
-
# Pass in the instance of the object that is using the errors object.
-
#
-
# class Person
-
# def initialize
-
# @errors = ActiveModel::Errors.new(self)
-
# end
-
# end
-
1
def initialize(base)
-
2774
@base = base
-
2774
@messages = {}
-
end
-
-
1
def initialize_dup(other) # :nodoc:
-
@messages = other.messages.dup
-
super
-
end
-
-
# Clear the error messages.
-
#
-
# person.errors.full_messages # => ["name can not be nil"]
-
# person.errors.clear
-
# person.errors.full_messages # => []
-
1
def clear
-
3407
messages.clear
-
end
-
-
# Returns +true+ if the error messages include an error for the given key
-
# +attribute+, +false+ otherwise.
-
#
-
# person.errors.messages # => {:name=>["can not be nil"]}
-
# person.errors.include?(:name) # => true
-
# person.errors.include?(:age) # => false
-
1
def include?(attribute)
-
(v = messages[attribute]) && v.any?
-
end
-
# aliases include?
-
1
alias :has_key? :include?
-
-
# Get messages for +key+.
-
#
-
# person.errors.messages # => {:name=>["can not be nil"]}
-
# person.errors.get(:name) # => ["can not be nil"]
-
# person.errors.get(:age) # => nil
-
1
def get(key)
-
1085
messages[key]
-
end
-
-
# Set messages for +key+ to +value+.
-
#
-
# person.errors.get(:name) # => ["can not be nil"]
-
# person.errors.set(:name, ["can't be nil"])
-
# person.errors.get(:name) # => ["can't be nil"]
-
1
def set(key, value)
-
308
messages[key] = value
-
end
-
-
# Delete messages for +key+. Returns the deleted messages.
-
#
-
# person.errors.get(:name) # => ["can not be nil"]
-
# person.errors.delete(:name) # => ["can not be nil"]
-
# person.errors.get(:name) # => nil
-
1
def delete(key)
-
messages.delete(key)
-
end
-
-
# When passed a symbol or a name of a method, returns an array of errors
-
# for the method.
-
#
-
# person.errors[:name] # => ["can not be nil"]
-
# person.errors['name'] # => ["can not be nil"]
-
1
def [](attribute)
-
1085
get(attribute.to_sym) || set(attribute.to_sym, [])
-
end
-
-
# Adds to the supplied attribute the supplied error message.
-
#
-
# person.errors[:name] = "must be set"
-
# person.errors[:name] # => ['must be set']
-
1
def []=(attribute, error)
-
self[attribute] << error
-
end
-
-
# Iterates through each error key, value pair in the error messages hash.
-
# Yields the attribute and the error for that attribute. If the attribute
-
# has more than one error message, yields once for each error message.
-
#
-
# person.errors.add(:name, "can't be blank")
-
# person.errors.each do |attribute, error|
-
# # Will yield :name and "can't be blank"
-
# end
-
#
-
# person.errors.add(:name, "must be specified")
-
# person.errors.each do |attribute, error|
-
# # Will yield :name and "can't be blank"
-
# # then yield :name and "must be specified"
-
# end
-
1
def each
-
6902
messages.each_key do |attribute|
-
1296
self[attribute].each { |error| yield attribute, error }
-
end
-
end
-
-
# Returns the number of error messages.
-
#
-
# person.errors.add(:name, "can't be blank")
-
# person.errors.size # => 1
-
# person.errors.add(:name, "must be specified")
-
# person.errors.size # => 2
-
1
def size
-
values.flatten.size
-
end
-
-
# Returns all message values.
-
#
-
# person.errors.messages # => {:name=>["can not be nil", "must be specified"]}
-
# person.errors.values # => [["can not be nil", "must be specified"]]
-
1
def values
-
messages.values
-
end
-
-
# Returns all message keys.
-
#
-
# person.errors.messages # => {:name=>["can not be nil", "must be specified"]}
-
# person.errors.keys # => [:name]
-
1
def keys
-
messages.keys
-
end
-
-
# Returns an array of error messages, with the attribute name included.
-
#
-
# person.errors.add(:name, "can't be blank")
-
# person.errors.add(:name, "must be specified")
-
# person.errors.to_a # => ["name can't be blank", "name must be specified"]
-
1
def to_a
-
4
full_messages
-
end
-
-
# Returns the number of error messages.
-
#
-
# person.errors.add(:name, "can't be blank")
-
# person.errors.count # => 1
-
# person.errors.add(:name, "must be specified")
-
# person.errors.count # => 2
-
1
def count
-
4
to_a.size
-
end
-
-
# Returns +true+ if no errors are found, +false+ otherwise.
-
# If the error message is a string it can be empty.
-
#
-
# person.errors.full_messages # => ["name can not be nil"]
-
# person.errors.empty? # => false
-
1
def empty?
-
7367
all? { |k, v| v && v.empty? && !v.is_a?(String) }
-
end
-
# aliases empty?
-
1
alias_method :blank?, :empty?
-
-
# Returns an xml formatted representation of the Errors hash.
-
#
-
# person.errors.add(:name, "can't be blank")
-
# person.errors.add(:name, "must be specified")
-
# person.errors.to_xml
-
# # =>
-
# # <?xml version=\"1.0\" encoding=\"UTF-8\"?>
-
# # <errors>
-
# # <error>name can't be blank</error>
-
# # <error>name must be specified</error>
-
# # </errors>
-
1
def to_xml(options={})
-
to_a.to_xml({ :root => "errors", :skip_types => true }.merge!(options))
-
end
-
-
# Returns a Hash that can be used as the JSON representation for this
-
# object. You can pass the <tt>:full_messages</tt> option. This determines
-
# if the json object should contain full messages or not (false by default).
-
#
-
# person.as_json # => {:name=>["can not be nil"]}
-
# person.as_json(full_messages: true) # => {:name=>["name can not be nil"]}
-
1
def as_json(options=nil)
-
to_hash(options && options[:full_messages])
-
end
-
-
# Returns a Hash of attributes with their error messages. If +full_messages+
-
# is +true+, it will contain full messages (see +full_message+).
-
#
-
# person.to_hash # => {:name=>["can not be nil"]}
-
# person.to_hash(true) # => {:name=>["name can not be nil"]}
-
1
def to_hash(full_messages = false)
-
if full_messages
-
messages = {}
-
self.messages.each do |attribute, array|
-
messages[attribute] = array.map { |message| full_message(attribute, message) }
-
end
-
messages
-
else
-
self.messages.dup
-
end
-
end
-
-
# Adds +message+ to the error messages on +attribute+. More than one error
-
# can be added to the same +attribute+. If no +message+ is supplied,
-
# <tt>:invalid</tt> is assumed.
-
#
-
# person.errors.add(:name)
-
# # => ["is invalid"]
-
# person.errors.add(:name, 'must be implemented')
-
# # => ["is invalid", "must be implemented"]
-
#
-
# person.errors.messages
-
# # => {:name=>["must be implemented", "is invalid"]}
-
#
-
# If +message+ is a symbol, it will be translated using the appropriate
-
# scope (see +generate_message+).
-
#
-
# If +message+ is a proc, it will be called, allowing for things like
-
# <tt>Time.now</tt> to be used within an error.
-
#
-
# If the <tt>:strict</tt> option is set to true will raise
-
# ActiveModel::StrictValidationFailed instead of adding the error.
-
# <tt>:strict</tt> option can also be set to any other exception.
-
#
-
# person.errors.add(:name, nil, strict: true)
-
# # => ActiveModel::StrictValidationFailed: name is invalid
-
# person.errors.add(:name, nil, strict: NameIsInvalid)
-
# # => NameIsInvalid: name is invalid
-
#
-
# person.errors.messages # => {}
-
1
def add(attribute, message = nil, options = {})
-
246
message = normalize_message(attribute, message, options)
-
246
if exception = options[:strict]
-
exception = ActiveModel::StrictValidationFailed if exception == true
-
raise exception, full_message(attribute, message)
-
end
-
-
246
self[attribute] << message
-
end
-
-
# Will add an error message to each of the attributes in +attributes+
-
# that is empty.
-
#
-
# person.errors.add_on_empty(:name)
-
# person.errors.messages
-
# # => {:name=>["can't be empty"]}
-
1
def add_on_empty(attributes, options = {})
-
71
Array(attributes).each do |attribute|
-
71
value = @base.send(:read_attribute_for_validation, attribute)
-
71
is_empty = value.respond_to?(:empty?) ? value.empty? : false
-
71
add(attribute, :empty, options) if value.nil? || is_empty
-
end
-
end
-
-
# Will add an error message to each of the attributes in +attributes+ that
-
# is blank (using Object#blank?).
-
#
-
# person.errors.add_on_blank(:name)
-
# person.errors.messages
-
# # => {:name=>["can't be blank"]}
-
1
def add_on_blank(attributes, options = {})
-
1388
Array(attributes).each do |attribute|
-
1388
value = @base.send(:read_attribute_for_validation, attribute)
-
1388
add(attribute, :blank, options) if value.blank?
-
end
-
end
-
-
# Returns +true+ if an error on the attribute with the given message is
-
# present, +false+ otherwise. +message+ is treated the same as for +add+.
-
#
-
# person.errors.add :name, :blank
-
# person.errors.added? :name, :blank # => true
-
1
def added?(attribute, message = nil, options = {})
-
message = normalize_message(attribute, message, options)
-
self[attribute].include? message
-
end
-
-
# Returns all the full error messages in an array.
-
#
-
# class Person
-
# validates_presence_of :name, :address, :email
-
# validates_length_of :name, in: 5..30
-
# end
-
#
-
# person = Person.create(address: '123 First St.')
-
# person.errors.full_messages
-
# # => ["Name is too short (minimum is 5 characters)", "Name can't be blank", "Email can't be blank"]
-
1
def full_messages
-
94
map { |attribute, message| full_message(attribute, message) }
-
end
-
-
# Returns a full message for a given attribute.
-
#
-
# person.errors.full_message(:name, 'is invalid') # => "Name is invalid"
-
1
def full_message(attribute, message)
-
47
return message if attribute == :base
-
45
attr_name = attribute.to_s.tr('.', '_').humanize
-
45
attr_name = @base.class.human_attribute_name(attribute, :default => attr_name)
-
45
I18n.t(:"errors.format", {
-
:default => "%{attribute} %{message}",
-
:attribute => attr_name,
-
:message => message
-
})
-
end
-
-
# Translates an error message in its default scope
-
# (<tt>activemodel.errors.messages</tt>).
-
#
-
# Error messages are first looked up in <tt>models.MODEL.attributes.ATTRIBUTE.MESSAGE</tt>,
-
# if it's not there, it's looked up in <tt>models.MODEL.MESSAGE</tt> and if
-
# that is not there also, it returns the translation of the default message
-
# (e.g. <tt>activemodel.errors.messages.MESSAGE</tt>). The translated model
-
# name, translated attribute name and the value are available for
-
# interpolation.
-
#
-
# When using inheritance in your models, it will check all the inherited
-
# models too, but only if the model itself hasn't been found. Say you have
-
# <tt>class Admin < User; end</tt> and you wanted the translation for
-
# the <tt>:blank</tt> error message for the <tt>title</tt> attribute,
-
# it looks for these translations:
-
#
-
# * <tt>activemodel.errors.models.admin.attributes.title.blank</tt>
-
# * <tt>activemodel.errors.models.admin.blank</tt>
-
# * <tt>activemodel.errors.models.user.attributes.title.blank</tt>
-
# * <tt>activemodel.errors.models.user.blank</tt>
-
# * any default you provided through the +options+ hash (in the <tt>activemodel.errors</tt> scope)
-
# * <tt>activemodel.errors.messages.blank</tt>
-
# * <tt>errors.attributes.title.blank</tt>
-
# * <tt>errors.messages.blank</tt>
-
1
def generate_message(attribute, type = :invalid, options = {})
-
244
type = options.delete(:message) if options[:message].is_a?(Symbol)
-
-
244
if @base.class.respond_to?(:i18n_scope)
-
244
defaults = @base.class.lookup_ancestors.map do |klass|
-
324
[ :"#{@base.class.i18n_scope}.errors.models.#{klass.model_name.i18n_key}.attributes.#{attribute}.#{type}",
-
:"#{@base.class.i18n_scope}.errors.models.#{klass.model_name.i18n_key}.#{type}" ]
-
end
-
else
-
defaults = []
-
end
-
-
244
defaults << options.delete(:message)
-
244
defaults << :"#{@base.class.i18n_scope}.errors.messages.#{type}" if @base.class.respond_to?(:i18n_scope)
-
244
defaults << :"errors.attributes.#{attribute}.#{type}"
-
244
defaults << :"errors.messages.#{type}"
-
-
244
defaults.compact!
-
244
defaults.flatten!
-
-
244
key = defaults.shift
-
244
value = (attribute != :base ? @base.send(:read_attribute_for_validation, attribute) : nil)
-
-
244
options = {
-
:default => defaults,
-
:model => @base.class.model_name.human,
-
:attribute => @base.class.human_attribute_name(attribute),
-
:value => value
-
}.merge!(options)
-
-
244
I18n.translate(key, options)
-
end
-
-
1
private
-
1
def normalize_message(attribute, message, options)
-
246
message ||= :invalid
-
-
246
case message
-
when Symbol
-
246
generate_message(attribute, message, options.except(*CALLBACKS_OPTIONS))
-
when Proc
-
message.call
-
else
-
message
-
end
-
end
-
end
-
-
# Raised when a validation cannot be corrected by end users and are considered
-
# exceptional.
-
#
-
# class Person
-
# include ActiveModel::Validations
-
#
-
# attr_accessor :name
-
#
-
# validates_presence_of :name, strict: true
-
# end
-
#
-
# person = Person.new
-
# person.name = nil
-
# person.valid?
-
# # => ActiveModel::StrictValidationFailed: Name can't be blank
-
1
class StrictValidationFailed < StandardError
-
end
-
end
-
1
module ActiveModel
-
# Raised when forbidden attributes are used for mass assignment.
-
#
-
# class Person < ActiveRecord::Base
-
# end
-
#
-
# params = ActionController::Parameters.new(name: 'Bob')
-
# Person.new(params)
-
# # => ActiveModel::ForbiddenAttributesError
-
#
-
# params.permit!
-
# Person.new(params)
-
# # => #<Person id: nil, name: "Bob">
-
1
class ForbiddenAttributesError < StandardError
-
end
-
-
1
module ForbiddenAttributesProtection # :nodoc:
-
1
protected
-
1
def sanitize_for_mass_assignment(attributes)
-
2833
if attributes.respond_to?(:permitted?) && !attributes.permitted?
-
1
raise ActiveModel::ForbiddenAttributesError
-
else
-
2832
attributes
-
end
-
end
-
end
-
end
-
1
module ActiveModel
-
1
module Lint
-
# == Active \Model \Lint \Tests
-
#
-
# You can test whether an object is compliant with the Active \Model API by
-
# including <tt>ActiveModel::Lint::Tests</tt> in your TestCase. It will
-
# include tests that tell you whether your object is fully compliant,
-
# or if not, which aspects of the API are not implemented.
-
#
-
# Note an object is not required to implement all APIs in order to work
-
# with Action Pack. This module only intends to provide guidance in case
-
# you want all features out of the box.
-
#
-
# These tests do not attempt to determine the semantic correctness of the
-
# returned values. For instance, you could implement <tt>valid?</tt> to
-
# always return true, and the tests would pass. It is up to you to ensure
-
# that the values are semantically meaningful.
-
#
-
# Objects you pass in are expected to return a compliant object from a call
-
# to <tt>to_model</tt>. It is perfectly fine for <tt>to_model</tt> to return
-
# +self+.
-
1
module Tests
-
-
# == Responds to <tt>to_key</tt>
-
#
-
# Returns an Enumerable of all (primary) key attributes
-
# or nil if <tt>model.persisted?</tt> is false. This is used by
-
# <tt>dom_id</tt> to generate unique ids for the object.
-
1
def test_to_key
-
1
assert model.respond_to?(:to_key), "The model should respond to to_key"
-
1
def model.persisted?() false end
-
1
assert model.to_key.nil?, "to_key should return nil when `persisted?` returns false"
-
end
-
-
# == Responds to <tt>to_param</tt>
-
#
-
# Returns a string representing the object's key suitable for use in URLs
-
# or +nil+ if <tt>model.persisted?</tt> is +false+.
-
#
-
# Implementers can decide to either raise an exception or provide a
-
# default in case the record uses a composite primary key. There are no
-
# tests for this behavior in lint because it doesn't make sense to force
-
# any of the possible implementation strategies on the implementer.
-
# However, if the resource is not persisted?, then <tt>to_param</tt>
-
# should always return +nil+.
-
1
def test_to_param
-
1
assert model.respond_to?(:to_param), "The model should respond to to_param"
-
1
def model.to_key() [1] end
-
1
def model.persisted?() false end
-
1
assert model.to_param.nil?, "to_param should return nil when `persisted?` returns false"
-
end
-
-
# == Responds to <tt>to_partial_path</tt>
-
#
-
# Returns a string giving a relative path. This is used for looking up
-
# partials. For example, a BlogPost model might return "blog_posts/blog_post"
-
1
def test_to_partial_path
-
1
assert model.respond_to?(:to_partial_path), "The model should respond to to_partial_path"
-
1
assert_kind_of String, model.to_partial_path
-
end
-
-
# == Responds to <tt>persisted?</tt>
-
#
-
# Returns a boolean that specifies whether the object has been persisted
-
# yet. This is used when calculating the URL for an object. If the object
-
# is not persisted, a form for that object, for instance, will route to
-
# the create action. If it is persisted, a form for the object will routes
-
# to the update action.
-
1
def test_persisted?
-
1
assert model.respond_to?(:persisted?), "The model should respond to persisted?"
-
1
assert_boolean model.persisted?, "persisted?"
-
end
-
-
# == \Naming
-
#
-
# Model.model_name must return a string with some convenience methods:
-
# <tt>:human</tt>, <tt>:singular</tt> and <tt>:plural</tt>. Check
-
# ActiveModel::Naming for more information.
-
1
def test_model_naming
-
1
assert model.class.respond_to?(:model_name), "The model should respond to model_name"
-
1
model_name = model.class.model_name
-
1
assert model_name.respond_to?(:to_str)
-
1
assert model_name.human.respond_to?(:to_str)
-
1
assert model_name.singular.respond_to?(:to_str)
-
1
assert model_name.plural.respond_to?(:to_str)
-
end
-
-
# == \Errors Testing
-
#
-
# Returns an object that implements [](attribute) defined which returns an
-
# Array of Strings that are the errors for the attribute in question.
-
# If localization is used, the Strings should be localized for the current
-
# locale. If no error is present, this method should return an empty Array.
-
1
def test_errors_aref
-
1
assert model.respond_to?(:errors), "The model should respond to errors"
-
1
assert model.errors[:hello].is_a?(Array), "errors#[] should return an Array"
-
end
-
-
1
private
-
1
def model
-
15
assert @model.respond_to?(:to_model), "The object should respond_to to_model"
-
15
@model.to_model
-
end
-
-
1
def assert_boolean(result, name)
-
1
assert result == true || result == false, "#{name} should be a boolean"
-
end
-
end
-
end
-
end
-
1
require 'active_support/inflector'
-
1
require 'active_support/core_ext/hash/except'
-
1
require 'active_support/core_ext/module/introspection'
-
-
1
module ActiveModel
-
1
class Name
-
1
include Comparable
-
-
1
attr_reader :singular, :plural, :element, :collection,
-
:singular_route_key, :route_key, :param_key, :i18n_key,
-
:name
-
-
1
alias_method :cache_key, :collection
-
-
##
-
# :method: ==
-
#
-
# :call-seq:
-
# ==(other)
-
#
-
# Equivalent to <tt>String#==</tt>. Returns +true+ if the class name and
-
# +other+ are equal, otherwise +false+.
-
#
-
# class BlogPost
-
# extend ActiveModel::Naming
-
# end
-
#
-
# BlogPost.model_name == 'BlogPost' # => true
-
# BlogPost.model_name == 'Blog Post' # => false
-
-
##
-
# :method: ===
-
#
-
# :call-seq:
-
# ===(other)
-
#
-
# Equivalent to <tt>#==</tt>.
-
#
-
# class BlogPost
-
# extend ActiveModel::Naming
-
# end
-
#
-
# BlogPost.model_name === 'BlogPost' # => true
-
# BlogPost.model_name === 'Blog Post' # => false
-
-
##
-
# :method: <=>
-
#
-
# :call-seq:
-
# ==(other)
-
#
-
# Equivalent to <tt>String#<=></tt>.
-
#
-
# class BlogPost
-
# extend ActiveModel::Naming
-
# end
-
#
-
# BlogPost.model_name <=> 'BlogPost' # => 0
-
# BlogPost.model_name <=> 'Blog' # => 1
-
# BlogPost.model_name <=> 'BlogPosts' # => -1
-
-
##
-
# :method: =~
-
#
-
# :call-seq:
-
# =~(regexp)
-
#
-
# Equivalent to <tt>String#=~</tt>. Match the class name against the given
-
# regexp. Returns the position where the match starts or +nil+ if there is
-
# no match.
-
#
-
# class BlogPost
-
# extend ActiveModel::Naming
-
# end
-
#
-
# BlogPost.model_name =~ /Post/ # => 4
-
# BlogPost.model_name =~ /\d/ # => nil
-
-
##
-
# :method: !~
-
#
-
# :call-seq:
-
# !~(regexp)
-
#
-
# Equivalent to <tt>String#!~</tt>. Match the class name against the given
-
# regexp. Returns +true+ if there is no match, otherwise +false+.
-
#
-
# class BlogPost
-
# extend ActiveModel::Naming
-
# end
-
#
-
# BlogPost.model_name !~ /Post/ # => false
-
# BlogPost.model_name !~ /\d/ # => true
-
-
##
-
# :method: eql?
-
#
-
# :call-seq:
-
# eql?(other)
-
#
-
# Equivalent to <tt>String#eql?</tt>. Returns +true+ if the class name and
-
# +other+ have the same length and content, otherwise +false+.
-
#
-
# class BlogPost
-
# extend ActiveModel::Naming
-
# end
-
#
-
# BlogPost.model_name.eql?('BlogPost') # => true
-
# BlogPost.model_name.eql?('Blog Post') # => false
-
-
##
-
# :method: to_s
-
#
-
# :call-seq:
-
# to_s()
-
#
-
# Returns the class name.
-
#
-
# class BlogPost
-
# extend ActiveModel::Naming
-
# end
-
#
-
# BlogPost.model_name.to_s # => "BlogPost"
-
-
##
-
# :method: to_str
-
#
-
# :call-seq:
-
# to_str()
-
#
-
# Equivalent to +to_s+.
-
1
delegate :==, :===, :<=>, :=~, :"!~", :eql?, :to_s,
-
:to_str, :to => :name
-
-
# Returns a new ActiveModel::Name instance. By default, the +namespace+
-
# and +name+ option will take the namespace and name of the given class
-
# respectively.
-
#
-
# module Foo
-
# class Bar
-
# end
-
# end
-
#
-
# ActiveModel::Name.new(Foo::Bar).to_s
-
# # => "Foo::Bar"
-
1
def initialize(klass, namespace = nil, name = nil)
-
37
@name = name || klass.name
-
-
37
raise ArgumentError, "Class name cannot be blank. You need to supply a name argument when anonymous class given" if @name.blank?
-
-
37
@unnamespaced = @name.sub(/^#{namespace.name}::/, '') if namespace
-
37
@klass = klass
-
37
@singular = _singularize(@name)
-
37
@plural = ActiveSupport::Inflector.pluralize(@singular)
-
37
@element = ActiveSupport::Inflector.underscore(ActiveSupport::Inflector.demodulize(@name))
-
37
@human = ActiveSupport::Inflector.humanize(@element)
-
37
@collection = ActiveSupport::Inflector.tableize(@name)
-
37
@param_key = (namespace ? _singularize(@unnamespaced) : @singular)
-
37
@i18n_key = @name.underscore.to_sym
-
-
37
@route_key = (namespace ? ActiveSupport::Inflector.pluralize(@param_key) : @plural.dup)
-
37
@singular_route_key = ActiveSupport::Inflector.singularize(@route_key)
-
37
@route_key << "_index" if @plural == @singular
-
end
-
-
# Transform the model name into a more humane format, using I18n. By default,
-
# it will underscore then humanize the class name.
-
#
-
# class BlogPost
-
# extend ActiveModel::Naming
-
# end
-
#
-
# BlogPost.model_name.human # => "Blog post"
-
#
-
# Specify +options+ with additional translating options.
-
1
def human(options={})
-
return @human unless @klass.respond_to?(:lookup_ancestors) &&
-
250
@klass.respond_to?(:i18n_scope)
-
-
250
defaults = @klass.lookup_ancestors.map do |klass|
-
332
klass.model_name.i18n_key
-
end
-
-
250
defaults << options[:default] if options[:default]
-
250
defaults << @human
-
-
250
options = { :scope => [@klass.i18n_scope, :models], :count => 1, :default => defaults }.merge!(options.except(:default))
-
250
I18n.translate(defaults.shift, options)
-
end
-
-
1
private
-
-
1
def _singularize(string, replacement='_')
-
37
ActiveSupport::Inflector.underscore(string).tr('/', replacement)
-
end
-
end
-
-
# == Active \Model \Naming
-
#
-
# Creates a +model_name+ method on your object.
-
#
-
# To implement, just extend ActiveModel::Naming in your object:
-
#
-
# class BookCover
-
# extend ActiveModel::Naming
-
# end
-
#
-
# BookCover.model_name # => "BookCover"
-
# BookCover.model_name.human # => "Book cover"
-
#
-
# BookCover.model_name.i18n_key # => :book_cover
-
# BookModule::BookCover.model_name.i18n_key # => :"book_module/book_cover"
-
#
-
# Providing the functionality that ActiveModel::Naming provides in your object
-
# is required to pass the Active Model Lint test. So either extending the
-
# provided method below, or rolling your own is required.
-
1
module Naming
-
# Returns an ActiveModel::Name object for module. It can be
-
# used to retrieve all kinds of naming-related information
-
# (See ActiveModel::Name for more information).
-
#
-
# class Person < ActiveModel::Model
-
# end
-
#
-
# Person.model_name # => Person
-
# Person.model_name.class # => ActiveModel::Name
-
# Person.model_name.singular # => "person"
-
# Person.model_name.plural # => "people"
-
1
def model_name
-
@_model_name ||= begin
-
37
namespace = self.parents.detect do |n|
-
41
n.respond_to?(:use_relative_model_naming?) && n.use_relative_model_naming?
-
end
-
37
ActiveModel::Name.new(self, namespace)
-
1710
end
-
end
-
-
# Returns the plural class name of a record or class.
-
#
-
# ActiveModel::Naming.plural(post) # => "posts"
-
# ActiveModel::Naming.plural(Highrise::Person) # => "highrise_people"
-
1
def self.plural(record_or_class)
-
model_name_from_record_or_class(record_or_class).plural
-
end
-
-
# Returns the singular class name of a record or class.
-
#
-
# ActiveModel::Naming.singular(post) # => "post"
-
# ActiveModel::Naming.singular(Highrise::Person) # => "highrise_person"
-
1
def self.singular(record_or_class)
-
model_name_from_record_or_class(record_or_class).singular
-
end
-
-
# Identifies whether the class name of a record or class is uncountable.
-
#
-
# ActiveModel::Naming.uncountable?(Sheep) # => true
-
# ActiveModel::Naming.uncountable?(Post) # => false
-
1
def self.uncountable?(record_or_class)
-
plural(record_or_class) == singular(record_or_class)
-
end
-
-
# Returns string to use while generating route names. It differs for
-
# namespaced models regarding whether it's inside isolated engine.
-
#
-
# # For isolated engine:
-
# ActiveModel::Naming.singular_route_key(Blog::Post) #=> post
-
#
-
# # For shared engine:
-
# ActiveModel::Naming.singular_route_key(Blog::Post) #=> blog_post
-
1
def self.singular_route_key(record_or_class)
-
model_name_from_record_or_class(record_or_class).singular_route_key
-
end
-
-
# Returns string to use while generating route names. It differs for
-
# namespaced models regarding whether it's inside isolated engine.
-
#
-
# # For isolated engine:
-
# ActiveModel::Naming.route_key(Blog::Post) #=> posts
-
#
-
# # For shared engine:
-
# ActiveModel::Naming.route_key(Blog::Post) #=> blog_posts
-
#
-
# The route key also considers if the noun is uncountable and, in
-
# such cases, automatically appends _index.
-
1
def self.route_key(record_or_class)
-
model_name_from_record_or_class(record_or_class).route_key
-
end
-
-
# Returns string to use for params names. It differs for
-
# namespaced models regarding whether it's inside isolated engine.
-
#
-
# # For isolated engine:
-
# ActiveModel::Naming.param_key(Blog::Post) #=> post
-
#
-
# # For shared engine:
-
# ActiveModel::Naming.param_key(Blog::Post) #=> blog_post
-
1
def self.param_key(record_or_class)
-
model_name_from_record_or_class(record_or_class).param_key
-
end
-
-
1
def self.model_name_from_record_or_class(record_or_class) #:nodoc:
-
if record_or_class.respond_to?(:model_name)
-
record_or_class.model_name
-
elsif record_or_class.respond_to?(:to_model)
-
record_or_class.to_model.class.model_name
-
else
-
record_or_class.class.model_name
-
end
-
end
-
1
private_class_method :model_name_from_record_or_class
-
end
-
end
-
1
require 'set'
-
-
1
module ActiveModel
-
# Stores the enabled/disabled state of individual observers for
-
# a particular model class.
-
1
class ObserverArray < Array
-
1
attr_reader :model_class
-
1
def initialize(model_class, *args) #:nodoc:
-
466
@model_class = model_class
-
466
super(*args)
-
end
-
-
# Returns +true+ if the given observer is disabled for the model class,
-
# +false+ otherwise.
-
1
def disabled_for?(observer) #:nodoc:
-
2130
disabled_observers.include?(observer.class)
-
end
-
-
# Disables one or more observers. This supports multiple forms:
-
#
-
# ORM.observers.disable :all
-
# # => disables all observers for all models subclassed from
-
# # an ORM base class that includes ActiveModel::Observing
-
# # e.g. ActiveRecord::Base
-
#
-
# ORM.observers.disable :user_observer
-
# # => disables the UserObserver
-
#
-
# User.observers.disable AuditTrail
-
# # => disables the AuditTrail observer for User notifications.
-
# # Other models will still notify the AuditTrail observer.
-
#
-
# ORM.observers.disable :observer_1, :observer_2
-
# # => disables Observer1 and Observer2 for all models.
-
#
-
# User.observers.disable :all do
-
# # all user observers are disabled for
-
# # just the duration of the block
-
# end
-
1
def disable(*observers, &block)
-
1
set_enablement(false, observers, &block)
-
end
-
-
# Enables one or more observers. This supports multiple forms:
-
#
-
# ORM.observers.enable :all
-
# # => enables all observers for all models subclassed from
-
# # an ORM base class that includes ActiveModel::Observing
-
# # e.g. ActiveRecord::Base
-
#
-
# ORM.observers.enable :user_observer
-
# # => enables the UserObserver
-
#
-
# User.observers.enable AuditTrail
-
# # => enables the AuditTrail observer for User notifications.
-
# # Other models will not be affected (i.e. they will not
-
# # trigger notifications to AuditTrail if previously disabled)
-
#
-
# ORM.observers.enable :observer_1, :observer_2
-
# # => enables Observer1 and Observer2 for all models.
-
#
-
# User.observers.enable :all do
-
# # all user observers are enabled for
-
# # just the duration of the block
-
# end
-
#
-
# Note: all observers are enabled by default. This method is only
-
# useful when you have previously disabled one or more observers.
-
1
def enable(*observers, &block)
-
set_enablement(true, observers, &block)
-
end
-
-
1
protected
-
-
1
def disabled_observers #:nodoc:
-
3436
@disabled_observers ||= Set.new
-
end
-
-
1
def observer_class_for(observer) #:nodoc:
-
653
return observer if observer.is_a?(Class)
-
-
if observer.respond_to?(:to_sym) # string/symbol
-
observer.to_s.camelize.constantize
-
else
-
raise ArgumentError, "#{observer} was not a class or a " +
-
"lowercase, underscored class name as expected."
-
end
-
end
-
-
1
def start_transaction #:nodoc:
-
653
disabled_observer_stack.push(disabled_observers.dup)
-
653
each_subclass_array do |array|
-
652
array.start_transaction
-
end
-
end
-
-
1
def disabled_observer_stack #:nodoc:
-
1306
@disabled_observer_stack ||= []
-
end
-
-
1
def end_transaction #:nodoc:
-
653
@disabled_observers = disabled_observer_stack.pop
-
653
each_subclass_array do |array|
-
652
array.end_transaction
-
end
-
end
-
-
1
def transaction #:nodoc:
-
1
start_transaction
-
-
1
begin
-
1
yield
-
ensure
-
1
end_transaction
-
end
-
end
-
-
1
def each_subclass_array #:nodoc:
-
1959
model_class.descendants.each do |subclass|
-
1956
yield subclass.observers
-
end
-
end
-
-
1
def set_enablement(enabled, observers) #:nodoc:
-
654
if block_given?
-
1
transaction do
-
1
set_enablement(enabled, observers)
-
1
yield
-
end
-
else
-
653
observers = ActiveModel::Observer.descendants if observers == [:all]
-
653
observers.each do |obs|
-
653
klass = observer_class_for(obs)
-
-
653
unless klass < ActiveModel::Observer
-
raise ArgumentError.new("#{obs} does not refer to a valid observer")
-
end
-
-
653
if enabled
-
disabled_observers.delete(klass)
-
else
-
653
disabled_observers << klass
-
end
-
end
-
-
653
each_subclass_array do |array|
-
652
array.set_enablement(enabled, observers)
-
end
-
end
-
end
-
end
-
end
-
1
require 'singleton'
-
1
require 'active_model/observer_array'
-
1
require 'active_support/core_ext/module/aliasing'
-
1
require 'active_support/core_ext/module/remove_method'
-
1
require 'active_support/core_ext/string/inflections'
-
1
require 'active_support/core_ext/enumerable'
-
1
require 'active_support/core_ext/object/try'
-
1
require 'active_support/descendants_tracker'
-
-
1
module ActiveModel
-
# == Active \Model Observers Activation
-
1
module Observing
-
1
extend ActiveSupport::Concern
-
-
1
included do
-
1
extend ActiveSupport::DescendantsTracker
-
end
-
-
1
module ClassMethods
-
# Activates the observers assigned.
-
#
-
# class ORM
-
# include ActiveModel::Observing
-
# end
-
#
-
# # Calls PersonObserver.instance
-
# ORM.observers = :person_observer
-
#
-
# # Calls Cacher.instance and GarbageCollector.instance
-
# ORM.observers = :cacher, :garbage_collector
-
#
-
# # Same as above, just using explicit class references
-
# ORM.observers = Cacher, GarbageCollector
-
#
-
# Note: Setting this does not instantiate the observers yet.
-
# <tt>instantiate_observers</tt> is called during startup, and before
-
# each development request.
-
1
def observers=(*values)
-
1
observers.replace(values.flatten)
-
end
-
-
# Gets an array of observers observing this model. The array also provides
-
# +enable+ and +disable+ methods that allow you to selectively enable and
-
# disable observers (see ActiveModel::ObserverArray.enable and
-
# ActiveModel::ObserverArray.disable for more on this).
-
#
-
# class ORM
-
# include ActiveModel::Observing
-
# end
-
#
-
# ORM.observers = :cacher, :garbage_collector
-
# ORM.observers # => [:cacher, :garbage_collector]
-
# ORM.observers.class # => ActiveModel::ObserverArray
-
1
def observers
-
4089
@observers ||= ObserverArray.new(self)
-
end
-
-
# Returns the current observer instances.
-
#
-
# class Foo
-
# include ActiveModel::Observing
-
#
-
# attr_accessor :status
-
# end
-
#
-
# class FooObserver < ActiveModel::Observer
-
# def on_spec(record, *args)
-
# record.status = true
-
# end
-
# end
-
#
-
# Foo.observers = FooObserver
-
# Foo.instantiate_observers
-
#
-
# Foo.observer_instances # => [#<FooObserver:0x007fc212c40820>]
-
1
def observer_instances
-
547
@observer_instances ||= []
-
end
-
-
# Instantiate the global observers.
-
#
-
# class Foo
-
# include ActiveModel::Observing
-
#
-
# attr_accessor :status
-
# end
-
#
-
# class FooObserver < ActiveModel::Observer
-
# def on_spec(record, *args)
-
# record.status = true
-
# end
-
# end
-
#
-
# Foo.observers = FooObserver
-
#
-
# foo = Foo.new
-
# foo.status = false
-
# foo.notify_observers(:on_spec)
-
# foo.status # => false
-
#
-
# Foo.instantiate_observers # => [FooObserver]
-
#
-
# foo = Foo.new
-
# foo.status = false
-
# foo.notify_observers(:on_spec)
-
# foo.status # => true
-
1
def instantiate_observers
-
2
observers.each { |o| instantiate_observer(o) }
-
end
-
-
# Add a new observer to the pool. The new observer needs to respond to
-
# <tt>update</tt>, otherwise it raises an +ArgumentError+ exception.
-
#
-
# class Foo
-
# include ActiveModel::Observing
-
# end
-
#
-
# class FooObserver < ActiveModel::Observer
-
# end
-
#
-
# Foo.add_observer(FooObserver.instance)
-
#
-
# Foo.observers_instance
-
# # => [#<FooObserver:0x007fccf55d9390>]
-
1
def add_observer(observer)
-
61
unless observer.respond_to? :update
-
raise ArgumentError, "observer needs to respond to 'update'"
-
end
-
61
observer_instances << observer
-
end
-
-
# Fires notifications to model's observers.
-
#
-
# def save
-
# notify_observers(:before_save)
-
# ...
-
# notify_observers(:after_save)
-
# end
-
#
-
# Custom notifications can be sent in a similar fashion:
-
#
-
# notify_observers(:custom_notification, :foo)
-
#
-
# This will call <tt>custom_notification</tt>, passing as arguments
-
# the current object and <tt>:foo</tt>.
-
1
def notify_observers(*args)
-
494
observer_instances.each { |observer| observer.update(*args) }
-
end
-
-
# Returns the total number of instantiated observers.
-
#
-
# class Foo
-
# include ActiveModel::Observing
-
#
-
# attr_accessor :status
-
# end
-
#
-
# class FooObserver < ActiveModel::Observer
-
# def on_spec(record, *args)
-
# record.status = true
-
# end
-
# end
-
#
-
# Foo.observers = FooObserver
-
# Foo.observers_count # => 0
-
# Foo.instantiate_observers
-
# Foo.observers_count # => 1
-
1
def observers_count
-
observer_instances.size
-
end
-
-
# <tt>count_observers</tt> is deprecated. Use #observers_count.
-
1
def count_observers
-
msg = "count_observers is deprecated in favor of observers_count"
-
ActiveSupport::Deprecation.warn msg
-
observers_count
-
end
-
-
1
protected
-
1
def instantiate_observer(observer) #:nodoc:
-
# string/symbol
-
1
if observer.respond_to?(:to_sym)
-
observer = observer.to_s.camelize.constantize
-
end
-
1
if observer.respond_to?(:instance)
-
observer.instance
-
else
-
1
raise ArgumentError,
-
"#{observer} must be a lowercase, underscored class name (or " +
-
"the class itself) responding to the method :instance. " +
-
"Example: Person.observers = :big_brother # calls " +
-
"BigBrother.instance"
-
end
-
end
-
-
# Notify observers when the observed class is subclassed.
-
1
def inherited(subclass) #:nodoc:
-
486
super
-
486
notify_observers :observed_class_inherited, subclass
-
end
-
end
-
-
# Notify a change to the list of observers.
-
#
-
# class Foo
-
# include ActiveModel::Observing
-
#
-
# attr_accessor :status
-
# end
-
#
-
# class FooObserver < ActiveModel::Observer
-
# def on_spec(record, *args)
-
# record.status = true
-
# end
-
# end
-
#
-
# Foo.observers = FooObserver
-
# Foo.instantiate_observers # => [FooObserver]
-
#
-
# foo = Foo.new
-
# foo.status = false
-
# foo.notify_observers(:on_spec)
-
# foo.status # => true
-
#
-
# See ActiveModel::Observing::ClassMethods.notify_observers for more
-
# information.
-
1
def notify_observers(method, *extra_args)
-
self.class.notify_observers(method, self, *extra_args)
-
end
-
end
-
-
# == Active \Model Observers
-
#
-
# Observer classes respond to life cycle callbacks to implement trigger-like
-
# behavior outside the original class. This is a great way to reduce the
-
# clutter that normally comes when the model class is burdened with
-
# functionality that doesn't pertain to the core responsibility of the
-
# class.
-
#
-
# class CommentObserver < ActiveModel::Observer
-
# def after_save(comment)
-
# Notifications.comment('admin@do.com', 'New comment was posted', comment).deliver
-
# end
-
# end
-
#
-
# This Observer sends an email when a <tt>Comment#save</tt> is finished.
-
#
-
# class ContactObserver < ActiveModel::Observer
-
# def after_create(contact)
-
# contact.logger.info('New contact added!')
-
# end
-
#
-
# def after_destroy(contact)
-
# contact.logger.warn("Contact with an id of #{contact.id} was destroyed!")
-
# end
-
# end
-
#
-
# This Observer uses logger to log when specific callbacks are triggered.
-
#
-
# == \Observing a class that can't be inferred
-
#
-
# Observers will by default be mapped to the class with which they share a
-
# name. So <tt>CommentObserver</tt> will be tied to observing <tt>Comment</tt>,
-
# <tt>ProductManagerObserver</tt> to <tt>ProductManager</tt>, and so on. If
-
# you want to name your observer differently than the class you're interested
-
# in observing, you can use the <tt>Observer.observe</tt> class method which
-
# takes either the concrete class (<tt>Product</tt>) or a symbol for that
-
# class (<tt>:product</tt>):
-
#
-
# class AuditObserver < ActiveModel::Observer
-
# observe :account
-
#
-
# def after_update(account)
-
# AuditTrail.new(account, 'UPDATED')
-
# end
-
# end
-
#
-
# If the audit observer needs to watch more than one kind of object, this can
-
# be specified with multiple arguments:
-
#
-
# class AuditObserver < ActiveModel::Observer
-
# observe :account, :balance
-
#
-
# def after_update(record)
-
# AuditTrail.new(record, 'UPDATED')
-
# end
-
# end
-
#
-
# The <tt>AuditObserver</tt> will now act on both updates to <tt>Account</tt>
-
# and <tt>Balance</tt> by treating them both as records.
-
#
-
# If you're using an Observer in a Rails application with Active Record, be
-
# sure to read about the necessary configuration in the documentation for
-
# ActiveRecord::Observer.
-
1
class Observer
-
1
include Singleton
-
1
extend ActiveSupport::DescendantsTracker
-
-
1
class << self
-
# Attaches the observer to the supplied model classes.
-
#
-
# class AuditObserver < ActiveModel::Observer
-
# observe :account, :balance
-
# end
-
#
-
# AuditObserver.observed_classes # => [Account, Balance]
-
1
def observe(*models)
-
11
models.flatten!
-
263
models.collect! { |model| model.respond_to?(:to_sym) ? model.to_s.camelize.constantize : model }
-
20
singleton_class.redefine_method(:observed_classes) { models }
-
end
-
-
# Returns an array of Classes to observe.
-
#
-
# AccountObserver.observed_classes # => [Account]
-
#
-
# You can override this instead of using the +observe+ helper.
-
#
-
# class AuditObserver < ActiveModel::Observer
-
# def self.observed_classes
-
# [Account, Balance]
-
# end
-
# end
-
1
def observed_classes
-
10
Array(observed_class)
-
end
-
-
# Returns the class observed by default. It's inferred from the observer's
-
# class name.
-
#
-
# PersonObserver.observed_class # => Person
-
# AccountObserver.observed_class # => Account
-
1
def observed_class
-
12
name[/(.*)Observer/, 1].try :constantize
-
end
-
end
-
-
# Start observing the declared classes and their subclasses.
-
# Called automatically by the instance method.
-
1
def initialize #:nodoc:
-
63
observed_classes.each { |klass| add_observer!(klass) }
-
end
-
-
1
def observed_classes #:nodoc:
-
18
self.class.observed_classes
-
end
-
-
# Send observed_method(object) if the method exists and
-
# the observer is enabled for the given object's class.
-
1
def update(observed_method, object, *extra_args, &block) #:nodoc:
-
2138
return if !respond_to?(observed_method) || disabled_for?(object)
-
2136
send(observed_method, object, *extra_args, &block)
-
end
-
-
# Special method sent by the observed class when it is inherited.
-
# Passes the new subclass.
-
1
def observed_class_inherited(subclass) #:nodoc:
-
8
self.class.observe(observed_classes + [subclass])
-
8
add_observer!(subclass)
-
end
-
-
1
protected
-
1
def add_observer!(klass) #:nodoc:
-
61
klass.add_observer(self)
-
end
-
-
# Returns true if notifications are disabled for this object.
-
1
def disabled_for?(object) #:nodoc:
-
2138
klass = object.class
-
2138
return false unless klass.respond_to?(:observers)
-
2130
klass.observers.disabled_for?(self)
-
end
-
end
-
end
-
1
module ActiveModel
-
1
module SecurePassword
-
1
extend ActiveSupport::Concern
-
-
1
module ClassMethods
-
# Adds methods to set and authenticate against a BCrypt password.
-
# This mechanism requires you to have a password_digest attribute.
-
#
-
# Validations for presence of password on create, confirmation of password
-
# (using a +password_confirmation+ attribute) are automatically added. If
-
# you wish to turn off validations, pass <tt>validations: false</tt> as an
-
# argument. You can add more validations by hand if need be.
-
#
-
# You need to add bcrypt-ruby (~> 3.0.0) to Gemfile to use #has_secure_password:
-
#
-
# gem 'bcrypt-ruby', '~> 3.0.0'
-
#
-
# Example using Active Record (which automatically includes ActiveModel::SecurePassword):
-
#
-
# # Schema: User(name:string, password_digest:string)
-
# class User < ActiveRecord::Base
-
# has_secure_password
-
# end
-
#
-
# user = User.new(name: 'david', password: '', password_confirmation: 'nomatch')
-
# user.save # => false, password required
-
# user.password = 'mUc3m00RsqyRe'
-
# user.save # => false, confirmation doesn't match
-
# user.password_confirmation = 'mUc3m00RsqyRe'
-
# user.save # => true
-
# user.authenticate('notright') # => false
-
# user.authenticate('mUc3m00RsqyRe') # => user
-
# User.find_by_name('david').try(:authenticate, 'notright') # => false
-
# User.find_by_name('david').try(:authenticate, 'mUc3m00RsqyRe') # => user
-
1
def has_secure_password(options = {})
-
# Load bcrypt-ruby only when has_secure_password is used.
-
# This is to avoid ActiveModel (and by extension the entire framework)
-
# being dependent on a binary library.
-
gem 'bcrypt-ruby', '~> 3.0.0'
-
require 'bcrypt'
-
-
attr_reader :password
-
-
if options.fetch(:validations, true)
-
validates_confirmation_of :password
-
validates_presence_of :password, :on => :create
-
-
before_create { raise "Password digest missing on new record" if password_digest.blank? }
-
end
-
-
include InstanceMethodsOnActivation
-
-
if respond_to?(:attributes_protected_by_default)
-
def self.attributes_protected_by_default #:nodoc:
-
super + ['password_digest']
-
end
-
end
-
end
-
end
-
-
1
module InstanceMethodsOnActivation
-
# Returns +self+ if the password is correct, otherwise +false+.
-
#
-
# class User < ActiveRecord::Base
-
# has_secure_password validations: false
-
# end
-
#
-
# user = User.new(name: 'david', password: 'mUc3m00RsqyRe')
-
# user.save
-
# user.authenticate('notright') # => false
-
# user.authenticate('mUc3m00RsqyRe') # => user
-
1
def authenticate(unencrypted_password)
-
BCrypt::Password.new(password_digest) == unencrypted_password && self
-
end
-
-
# Encrypts the password into the +password_digest+ attribute, only if the
-
# new password is not blank.
-
#
-
# class User < ActiveRecord::Base
-
# has_secure_password validations: false
-
# end
-
#
-
# user = User.new
-
# user.password = nil
-
# user.password_digest # => nil
-
# user.password = 'mUc3m00RsqyRe'
-
# user.password_digest # => "$2a$10$4LEA7r4YmNHtvlAvHhsYAeZmk/xeUVtMTYqwIvYY76EW5GUqDiP4."
-
1
def password=(unencrypted_password)
-
unless unencrypted_password.blank?
-
@password = unencrypted_password
-
self.password_digest = BCrypt::Password.create(unencrypted_password)
-
end
-
end
-
end
-
end
-
end
-
1
require 'active_support/core_ext/hash/except'
-
1
require 'active_support/core_ext/hash/slice'
-
-
1
module ActiveModel
-
# == Active \Model \Serialization
-
#
-
# Provides a basic serialization to a serializable_hash for your object.
-
#
-
# A minimal implementation could be:
-
#
-
# class Person
-
# include ActiveModel::Serialization
-
#
-
# attr_accessor :name
-
#
-
# def attributes
-
# {'name' => nil}
-
# end
-
# end
-
#
-
# Which would provide you with:
-
#
-
# person = Person.new
-
# person.serializable_hash # => {"name"=>nil}
-
# person.name = "Bob"
-
# person.serializable_hash # => {"name"=>"Bob"}
-
#
-
# You need to declare an attributes hash which contains the attributes you
-
# want to serialize. Attributes must be strings, not symbols. When called,
-
# serializable hash will use instance methods that match the name of the
-
# attributes hash's keys. In order to override this behavior, take a look at
-
# the private method +read_attribute_for_serialization+.
-
#
-
# Most of the time though, you will want to include the JSON or XML
-
# serializations. Both of these modules automatically include the
-
# <tt>ActiveModel::Serialization</tt> module, so there is no need to
-
# explicitly include it.
-
#
-
# A minimal implementation including XML and JSON would be:
-
#
-
# class Person
-
# include ActiveModel::Serializers::JSON
-
# include ActiveModel::Serializers::Xml
-
#
-
# attr_accessor :name
-
#
-
# def attributes
-
# {'name' => nil}
-
# end
-
# end
-
#
-
# Which would provide you with:
-
#
-
# person = Person.new
-
# person.serializable_hash # => {"name"=>nil}
-
# person.as_json # => {"name"=>nil}
-
# person.to_json # => "{\"name\":null}"
-
# person.to_xml # => "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<serial-person...
-
#
-
# person.name = "Bob"
-
# person.serializable_hash # => {"name"=>"Bob"}
-
# person.as_json # => {"name"=>"Bob"}
-
# person.to_json # => "{\"name\":\"Bob\"}"
-
# person.to_xml # => "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<serial-person...
-
#
-
# Valid options are <tt>:only</tt>, <tt>:except</tt>, <tt>:methods</tt> and
-
# <tt>:include</tt>. The following are all valid examples:
-
#
-
# person.serializable_hash(only: 'name')
-
# person.serializable_hash(include: :address)
-
# person.serializable_hash(include: { address: { only: 'city' }})
-
1
module Serialization
-
# Returns a serialized hash of your object.
-
#
-
# class Person
-
# include ActiveModel::Serialization
-
#
-
# attr_accessor :name, :age
-
#
-
# def attributes
-
# {'name' => nil, 'age' => nil}
-
# end
-
#
-
# def capitalized_name
-
# name.capitalize
-
# end
-
# end
-
#
-
# person = Person.new
-
# person.name = 'bob'
-
# person.age = 22
-
# person.serializable_hash # => {"name"=>"bob", "age"=>22}
-
# person.serializable_hash(only: :name) # => {"name"=>"bob"}
-
# person.serializable_hash(except: :name) # => {"age"=>22}
-
# person.serializable_hash(methods: :capitalized_name)
-
# # => {"name"=>"bob", "age"=>22, "capitalized_name"=>"Bob"}
-
1
def serializable_hash(options = nil)
-
199
options ||= {}
-
-
199
attribute_names = attributes.keys
-
199
if only = options[:only]
-
43
attribute_names &= Array(only).map(&:to_s)
-
elsif except = options[:except]
-
156
attribute_names -= Array(except).map(&:to_s)
-
end
-
-
199
hash = {}
-
1626
attribute_names.each { |n| hash[n] = read_attribute_for_serialization(n) }
-
-
208
Array(options[:methods]).each { |m| hash[m.to_s] = send(m) if respond_to?(m) }
-
-
199
serializable_add_includes(options) do |association, records, opts|
-
20
hash[association.to_s] = if records.respond_to?(:to_ary)
-
68
records.to_ary.map { |a| a.serializable_hash(opts) }
-
else
-
2
records.serializable_hash(opts)
-
end
-
end
-
-
199
hash
-
end
-
-
1
private
-
-
# Hook method defining how an attribute value should be retrieved for
-
# serialization. By default this is assumed to be an instance named after
-
# the attribute. Override this method in subclasses should you need to
-
# retrieve the value for a given attribute differently:
-
#
-
# class MyClass
-
# include ActiveModel::Validations
-
#
-
# def initialize(data = {})
-
# @data = data
-
# end
-
#
-
# def read_attribute_for_serialization(key)
-
# @data[key]
-
# end
-
# end
-
1
alias :read_attribute_for_serialization :send
-
-
# Add associations specified via the <tt>:include</tt> option.
-
#
-
# Expects a block that takes as arguments:
-
# +association+ - name of the association
-
# +records+ - the association record(s) to be serialized
-
# +opts+ - options for the association records
-
1
def serializable_add_includes(options = {}) #:nodoc:
-
316
return unless includes = options[:include]
-
-
42
unless includes.is_a?(Hash)
-
47
includes = Hash[Array(includes).map { |n| n.is_a?(Hash) ? n.to_a.first : [n, {}] }]
-
end
-
-
42
includes.each do |association, opts|
-
43
if records = send(association)
-
41
yield association, records, opts
-
end
-
end
-
end
-
end
-
end
-
1
require 'active_support/json'
-
-
1
module ActiveModel
-
1
module Serializers
-
# == Active Model JSON Serializer
-
1
module JSON
-
1
extend ActiveSupport::Concern
-
1
include ActiveModel::Serialization
-
-
1
included do
-
1
extend ActiveModel::Naming
-
-
1
class_attribute :include_root_in_json
-
1
self.include_root_in_json = false
-
end
-
-
# Returns a hash representing the model. Some configuration can be
-
# passed through +options+.
-
#
-
# The option <tt>include_root_in_json</tt> controls the top-level behavior
-
# of +as_json+. If +true+, +as_json+ will emit a single root node named
-
# after the object's type. The default value for <tt>include_root_in_json</tt>
-
# option is +false+.
-
#
-
# user = User.find(1)
-
# user.as_json
-
# # => { "id" => 1, "name" => "Konata Izumi", "age" => 16,
-
# # "created_at" => "2006/08/01", "awesome" => true}
-
#
-
# ActiveRecord::Base.include_root_in_json = true
-
#
-
# user.as_json
-
# # => { "user" => { "id" => 1, "name" => "Konata Izumi", "age" => 16,
-
# # "created_at" => "2006/08/01", "awesome" => true } }
-
#
-
# This behavior can also be achieved by setting the <tt>:root</tt> option
-
# to +true+ as in:
-
#
-
# user = User.find(1)
-
# user.as_json(root: true)
-
# # => { "user" => { "id" => 1, "name" => "Konata Izumi", "age" => 16,
-
# # "created_at" => "2006/08/01", "awesome" => true } }
-
#
-
# Without any +options+, the returned Hash will include all the model's
-
# attributes.
-
#
-
# user = User.find(1)
-
# user.as_json
-
# # => { "id" => 1, "name" => "Konata Izumi", "age" => 16,
-
# # "created_at" => "2006/08/01", "awesome" => true}
-
#
-
# The <tt>:only</tt> and <tt>:except</tt> options can be used to limit
-
# the attributes included, and work similar to the +attributes+ method.
-
#
-
# user.as_json(only: [:id, :name])
-
# # => { "id" => 1, "name" => "Konata Izumi" }
-
#
-
# user.as_json(except: [:id, :created_at, :age])
-
# # => { "name" => "Konata Izumi", "awesome" => true }
-
#
-
# To include the result of some method calls on the model use <tt>:methods</tt>:
-
#
-
# user.as_json(methods: :permalink)
-
# # => { "id" => 1, "name" => "Konata Izumi", "age" => 16,
-
# # "created_at" => "2006/08/01", "awesome" => true,
-
# # "permalink" => "1-konata-izumi" }
-
#
-
# To include associations use <tt>:include</tt>:
-
#
-
# user.as_json(include: :posts)
-
# # => { "id" => 1, "name" => "Konata Izumi", "age" => 16,
-
# # "created_at" => "2006/08/01", "awesome" => true,
-
# # "posts" => [ { "id" => 1, "author_id" => 1, "title" => "Welcome to the weblog" },
-
# # { "id" => 2, "author_id" => 1, "title" => "So I was thinking" } ] }
-
#
-
# Second level and higher order associations work as well:
-
#
-
# user.as_json(include: { posts: {
-
# include: { comments: {
-
# only: :body } },
-
# only: :title } })
-
# # => { "id" => 1, "name" => "Konata Izumi", "age" => 16,
-
# # "created_at" => "2006/08/01", "awesome" => true,
-
# # "posts" => [ { "comments" => [ { "body" => "1st post!" }, { "body" => "Second!" } ],
-
# # "title" => "Welcome to the weblog" },
-
# # { "comments" => [ { "body" => "Don't think too hard" } ],
-
# # "title" => "So I was thinking" } ] }
-
1
def as_json(options = nil)
-
29
root = if options && options.key?(:root)
-
options[:root]
-
else
-
29
include_root_in_json
-
end
-
-
29
if root
-
25
root = self.class.model_name.element if root == true
-
25
{ root => serializable_hash(options) }
-
else
-
4
serializable_hash(options)
-
end
-
end
-
-
# Sets the model +attributes+ from a JSON string. Returns +self+.
-
#
-
# class Person
-
# include ActiveModel::Serializers::JSON
-
#
-
# attr_accessor :name, :age, :awesome
-
#
-
# def attributes=(hash)
-
# hash.each do |key, value|
-
# instance_variable_set("@#{key}", value)
-
# end
-
# end
-
#
-
# def attributes
-
# instance_values
-
# end
-
# end
-
#
-
# json = { name: 'bob', age: 22, awesome:true }.to_json
-
# person = Person.new
-
# person.from_json(json) # => #<Person:0x007fec5e7a0088 @age=22, @awesome=true, @name="bob">
-
# person.name # => "bob"
-
# person.age # => 22
-
# person.awesome # => true
-
#
-
# The default value for +include_root+ is +false+. You can change it to
-
# +true+ if the given JSON string includes a single root node.
-
#
-
# json = { person: { name: 'bob', age: 22, awesome:true } }.to_json
-
# person = Person.new
-
# person.from_json(json) # => #<Person:0x007fec5e7a0088 @age=22, @awesome=true, @name="bob">
-
# person.name # => "bob"
-
# person.age # => 22
-
# person.awesome # => true
-
1
def from_json(json, include_root=include_root_in_json)
-
3
hash = ActiveSupport::JSON.decode(json)
-
3
hash = hash.values.first if include_root
-
3
self.attributes = hash
-
3
self
-
end
-
end
-
end
-
end
-
1
require 'active_support/core_ext/class/attribute_accessors'
-
1
require 'active_support/core_ext/array/conversions'
-
1
require 'active_support/core_ext/hash/conversions'
-
1
require 'active_support/core_ext/hash/slice'
-
-
1
module ActiveModel
-
1
module Serializers
-
# == Active Model XML Serializer
-
1
module Xml
-
1
extend ActiveSupport::Concern
-
1
include ActiveModel::Serialization
-
-
1
included do
-
1
extend ActiveModel::Naming
-
end
-
-
1
class Serializer #:nodoc:
-
1
class Attribute #:nodoc:
-
1
attr_reader :name, :value, :type
-
-
1
def initialize(name, serializable, value)
-
1006
@name, @serializable = name, serializable
-
1006
value = value.in_time_zone if value.respond_to?(:in_time_zone)
-
1006
@value = value
-
1006
@type = compute_type
-
end
-
-
1
def decorations
-
1006
decorations = {}
-
1006
decorations[:encoding] = 'base64' if type == :binary
-
1006
decorations[:type] = (type == :string) ? nil : type
-
1006
decorations[:nil] = true if value.nil?
-
1006
decorations
-
end
-
-
1
protected
-
-
1
def compute_type
-
42
return if value.nil?
-
25
type = ActiveSupport::XmlMini::TYPE_NAMES[value.class.name]
-
25
type ||= :string if value.respond_to?(:to_str)
-
25
type ||= :yaml
-
25
type
-
end
-
end
-
-
1
class MethodAttribute < Attribute #:nodoc:
-
end
-
-
1
attr_reader :options
-
-
1
def initialize(serializable, options = nil)
-
117
@serializable = serializable
-
117
@options = options ? options.dup : {}
-
end
-
-
1
def serializable_hash
-
117
@serializable.serializable_hash(@options.except(:include))
-
end
-
-
1
def serializable_collection
-
117
methods = Array(options[:methods]).map(&:to_s)
-
117
serializable_hash.map do |name, value|
-
1006
name = name.to_s
-
1006
if methods.include?(name)
-
5
self.class::MethodAttribute.new(name, @serializable, value)
-
else
-
1001
self.class::Attribute.new(name, @serializable, value)
-
end
-
end
-
end
-
-
1
def serialize
-
117
require 'builder' unless defined? ::Builder
-
-
117
options[:indent] ||= 2
-
117
options[:builder] ||= ::Builder::XmlMarkup.new(:indent => options[:indent])
-
-
117
@builder = options[:builder]
-
117
@builder.instruct! unless options[:skip_instruct]
-
-
117
root = (options[:root] || @serializable.class.model_name.element).to_s
-
117
root = ActiveSupport::XmlMini.rename_key(root, options)
-
-
117
args = [root]
-
117
args << {:xmlns => options[:namespace]} if options[:namespace]
-
117
args << {:type => options[:type]} if options[:type] && !options[:skip_types]
-
-
117
@builder.tag!(*args) do
-
117
add_attributes_and_methods
-
117
add_includes
-
117
add_extra_behavior
-
117
add_procs
-
117
yield @builder if block_given?
-
end
-
end
-
-
1
private
-
-
1
def add_extra_behavior
-
end
-
-
1
def add_attributes_and_methods
-
117
serializable_collection.each do |attribute|
-
1006
key = ActiveSupport::XmlMini.rename_key(attribute.name, options)
-
1006
ActiveSupport::XmlMini.to_tag(key, attribute.value,
-
options.merge(attribute.decorations))
-
end
-
end
-
-
1
def add_includes
-
117
@serializable.send(:serializable_add_includes, options) do |association, records, opts|
-
21
add_associations(association, records, opts)
-
end
-
end
-
-
# TODO: This can likely be cleaned up to simple use ActiveSupport::XmlMini.to_tag as well.
-
1
def add_associations(association, records, opts)
-
21
merged_options = opts.merge(options.slice(:builder, :indent))
-
21
merged_options[:skip_instruct] = true
-
-
21
[:skip_types, :dasherize, :camelize].each do |key|
-
63
merged_options[key] = options[key] if merged_options[key].nil? && !options[key].nil?
-
end
-
-
21
if records.respond_to?(:to_ary)
-
14
records = records.to_ary
-
-
14
tag = ActiveSupport::XmlMini.rename_key(association.to_s, options)
-
14
type = options[:skip_types] ? { } : {:type => "array"}
-
14
association_name = association.to_s.singularize
-
14
merged_options[:root] = association_name
-
-
14
if records.empty?
-
2
@builder.tag!(tag, type)
-
else
-
12
@builder.tag!(tag, type) do
-
12
records.each do |record|
-
40
if options[:skip_types]
-
3
record_type = {}
-
else
-
37
record_class = (record.class.to_s.underscore == association_name) ? nil : record.class.name
-
37
record_type = {:type => record_class}
-
end
-
-
40
record.to_xml merged_options.merge(record_type)
-
end
-
end
-
end
-
else
-
7
merged_options[:root] = association.to_s
-
7
records.to_xml(merged_options)
-
end
-
end
-
-
1
def add_procs
-
117
if procs = options.delete(:procs)
-
8
Array(procs).each do |proc|
-
8
if proc.arity == 1
-
7
proc.call(options)
-
else
-
1
proc.call(options, @serializable)
-
end
-
end
-
end
-
end
-
end
-
-
# Returns XML representing the model. Configuration can be
-
# passed through +options+.
-
#
-
# Without any +options+, the returned XML string will include all the
-
# model's attributes.
-
#
-
# user = User.find(1)
-
# user.to_xml
-
#
-
# <?xml version="1.0" encoding="UTF-8"?>
-
# <user>
-
# <id type="integer">1</id>
-
# <name>David</name>
-
# <age type="integer">16</age>
-
# <created-at type="dateTime">2011-01-30T22:29:23Z</created-at>
-
# </user>
-
#
-
# The <tt>:only</tt> and <tt>:except</tt> options can be used to limit the
-
# attributes included, and work similar to the +attributes+ method.
-
#
-
# To include the result of some method calls on the model use <tt>:methods</tt>.
-
#
-
# To include associations use <tt>:include</tt>.
-
#
-
# For further documentation, see <tt>ActiveRecord::Serialization#to_xml</tt>
-
1
def to_xml(options = {}, &block)
-
Serializer.new(self, options).serialize(&block)
-
end
-
-
# Sets the model +attributes+ from a JSON string. Returns +self+.
-
#
-
# class Person
-
# include ActiveModel::Serializers::Xml
-
#
-
# attr_accessor :name, :age, :awesome
-
#
-
# def attributes=(hash)
-
# hash.each do |key, value|
-
# instance_variable_set("@#{key}", value)
-
# end
-
# end
-
#
-
# def attributes
-
# instance_values
-
# end
-
# end
-
#
-
# xml = { name: 'bob', age: 22, awesome:true }.to_xml
-
# person = Person.new
-
# person.from_xml(xml) # => #<Person:0x007fec5e3b3c40 @age=22, @awesome=true, @name="bob">
-
# person.name # => "bob"
-
# person.age # => 22
-
# person.awesome # => true
-
1
def from_xml(xml)
-
3
self.attributes = Hash.from_xml(xml).values.first
-
3
self
-
end
-
end
-
end
-
end
-
1
module ActiveModel
-
-
# == Active \Model \Translation
-
#
-
# Provides integration between your object and the Rails internationalization
-
# (i18n) framework.
-
#
-
# A minimal implementation could be:
-
#
-
# class TranslatedPerson
-
# extend ActiveModel::Translation
-
# end
-
#
-
# TranslatedPerson.human_attribute_name('my_attribute')
-
# # => "My attribute"
-
#
-
# This also provides the required class methods for hooking into the
-
# Rails internationalization API, including being able to define a
-
# class based +i18n_scope+ and +lookup_ancestors+ to find translations in
-
# parent classes.
-
1
module Translation
-
1
include ActiveModel::Naming
-
-
# Returns the +i18n_scope+ for the class. Overwrite if you want custom lookup.
-
1
def i18n_scope
-
:activemodel
-
end
-
-
# When localizing a string, it goes through the lookup returned by this
-
# method, which is used in ActiveModel::Name#human,
-
# ActiveModel::Errors#full_messages and
-
# ActiveModel::Translation#human_attribute_name.
-
1
def lookup_ancestors
-
self.ancestors.select { |x| x.respond_to?(:model_name) }
-
end
-
-
# Transforms attribute names into a more human format, such as "First name"
-
# instead of "first_name".
-
#
-
# Person.human_attribute_name("first_name") # => "First name"
-
#
-
# Specify +options+ with additional translating options.
-
1
def human_attribute_name(attribute, options = {})
-
296
options = { :count => 1 }.merge!(options)
-
296
parts = attribute.to_s.split(".")
-
296
attribute = parts.pop
-
296
namespace = parts.join("/") unless parts.empty?
-
296
attributes_scope = "#{self.i18n_scope}.attributes"
-
-
296
if namespace
-
7
defaults = lookup_ancestors.map do |klass|
-
7
:"#{attributes_scope}.#{klass.model_name.i18n_key}/#{namespace}.#{attribute}"
-
end
-
7
defaults << :"#{attributes_scope}.#{namespace}.#{attribute}"
-
else
-
289
defaults = lookup_ancestors.map do |klass|
-
397
:"#{attributes_scope}.#{klass.model_name.i18n_key}.#{attribute}"
-
end
-
end
-
-
296
defaults << :"attributes.#{attribute}"
-
296
defaults << options.delete(:default) if options[:default]
-
296
defaults << attribute.humanize
-
-
296
options[:default] = defaults
-
296
I18n.translate(defaults.shift, options)
-
end
-
end
-
end
-
1
require 'active_support/core_ext/array/extract_options'
-
1
require 'active_support/core_ext/hash/keys'
-
1
require 'active_support/core_ext/hash/except'
-
1
require 'active_model/errors'
-
1
require 'active_model/validations/callbacks'
-
1
require 'active_model/validator'
-
-
1
module ActiveModel
-
-
# == Active \Model Validations
-
#
-
# Provides a full validation framework to your objects.
-
#
-
# A minimal implementation could be:
-
#
-
# class Person
-
# include ActiveModel::Validations
-
#
-
# attr_accessor :first_name, :last_name
-
#
-
# validates_each :first_name, :last_name do |record, attr, value|
-
# record.errors.add attr, 'starts with z.' if value.to_s[0] == ?z
-
# end
-
# end
-
#
-
# Which provides you with the full standard validation stack that you
-
# know from Active Record:
-
#
-
# person = Person.new
-
# person.valid? # => true
-
# person.invalid? # => false
-
#
-
# person.first_name = 'zoolander'
-
# person.valid? # => false
-
# person.invalid? # => true
-
# person.errors.messages # => {first_name:["starts with z."]}
-
#
-
# Note that <tt>ActiveModel::Validations</tt> automatically adds an +errors+
-
# method to your instances initialized with a new <tt>ActiveModel::Errors</tt>
-
# object, so there is no need for you to do this manually.
-
1
module Validations
-
1
extend ActiveSupport::Concern
-
-
1
included do
-
1
extend ActiveModel::Callbacks
-
1
extend ActiveModel::Translation
-
-
1
extend HelperMethods
-
1
include HelperMethods
-
-
1
attr_accessor :validation_context
-
1
define_callbacks :validate, :scope => :name
-
-
1
class_attribute :_validators
-
37
self._validators = Hash.new { |h,k| h[k] = [] }
-
end
-
-
1
module ClassMethods
-
# Validates each attribute against a block.
-
#
-
# class Person
-
# include ActiveModel::Validations
-
#
-
# attr_accessor :first_name, :last_name
-
#
-
# validates_each :first_name, :last_name, allow_blank: true do |record, attr, value|
-
# record.errors.add attr, 'starts with z.' if value.to_s[0] == ?z
-
# end
-
# end
-
#
-
# Options:
-
# * <tt>:on</tt> - Specifies the context where this validation is active
-
# (e.g. <tt>on: :create</tt> or <tt>on: :custom_validation_context</tt>)
-
# * <tt>:allow_nil</tt> - Skip validation if attribute is +nil+.
-
# * <tt>:allow_blank</tt> - Skip validation if attribute is blank.
-
# * <tt>:if</tt> - Specifies a method, proc or string to call to determine
-
# if the validation should occur (e.g. <tt>if: :allow_validation</tt>,
-
# or <tt>if: Proc.new { |user| user.signup_step > 2 }</tt>). The method,
-
# proc or string should return or evaluate to a +true+ or +false+ value.
-
# * <tt>:unless</tt> - Specifies a method, proc or string to call to
-
# determine if the validation should not occur (e.g. <tt>unless: :skip_validation</tt>,
-
# or <tt>unless: Proc.new { |user| user.signup_step <= 2 }</tt>). The
-
# method, proc or string should return or evaluate to a +true+ or +false+
-
# value.
-
1
def validates_each(*attr_names, &block)
-
validates_with BlockValidator, _merge_attributes(attr_names), &block
-
end
-
-
# Adds a validation method or block to the class. This is useful when
-
# overriding the +validate+ instance method becomes too unwieldy and
-
# you're looking for more descriptive declaration of your validations.
-
#
-
# This can be done with a symbol pointing to a method:
-
#
-
# class Comment
-
# include ActiveModel::Validations
-
#
-
# validate :must_be_friends
-
#
-
# def must_be_friends
-
# errors.add(:base, 'Must be friends to leave a comment') unless commenter.friend_of?(commentee)
-
# end
-
# end
-
#
-
# With a block which is passed with the current record to be validated:
-
#
-
# class Comment
-
# include ActiveModel::Validations
-
#
-
# validate do |comment|
-
# comment.must_be_friends
-
# end
-
#
-
# def must_be_friends
-
# errors.add(:base, 'Must be friends to leave a comment') unless commenter.friend_of?(commentee)
-
# end
-
# end
-
#
-
# Or with a block where self points to the current record to be validated:
-
#
-
# class Comment
-
# include ActiveModel::Validations
-
#
-
# validate do
-
# errors.add(:base, 'Must be friends to leave a comment') unless commenter.friend_of?(commentee)
-
# end
-
# end
-
#
-
# Options:
-
# * <tt>:on</tt> - Specifies the context where this validation is active
-
# (e.g. <tt>on: :create</tt> or <tt>on: :custom_validation_context</tt>)
-
# * <tt>:allow_nil</tt> - Skip validation if attribute is +nil+.
-
# * <tt>:allow_blank</tt> - Skip validation if attribute is blank.
-
# * <tt>:if</tt> - Specifies a method, proc or string to call to determine
-
# if the validation should occur (e.g. <tt>if: :allow_validation</tt>,
-
# or <tt>if: Proc.new { |user| user.signup_step > 2 }</tt>). The method,
-
# proc or string should return or evaluate to a +true+ or +false+ value.
-
# * <tt>:unless</tt> - Specifies a method, proc or string to call to
-
# determine if the validation should not occur (e.g. <tt>unless: :skip_validation</tt>,
-
# or <tt>unless: Proc.new { |user| user.signup_step <= 2 }</tt>). The
-
# method, proc or string should return or evaluate to a +true+ or +false+
-
# value.
-
1
def validate(*args, &block)
-
436
options = args.extract_options!
-
436
if options.key?(:on)
-
6
options = options.dup
-
6
options[:if] = Array(options[:if])
-
6
options[:if].unshift("validation_context == :#{options[:on]}")
-
end
-
436
args << options
-
436
set_callback(:validate, *args, &block)
-
end
-
-
# List all validators that are being used to validate the model using
-
# +validates_with+ method.
-
#
-
# class Person
-
# include ActiveModel::Validations
-
#
-
# validates_with MyValidator
-
# validates_with OtherValidator, on: :create
-
# validates_with StrictValidator, strict: true
-
# end
-
#
-
# Person.validators
-
# # => [
-
# # #<MyValidator:0x007fbff403e808 @options={}>,
-
# # #<OtherValidator:0x007fbff403d930 @options={on: :create}>,
-
# # #<StrictValidator:0x007fbff3204a30 @options={strict:true}>
-
# # ]
-
1
def validators
-
2
_validators.values.flatten.uniq
-
end
-
-
# List all validators that are being used to validate a specific attribute.
-
#
-
# class Person
-
# include ActiveModel::Validations
-
#
-
# attr_accessor :name , :age
-
#
-
# validates_presence_of :name
-
# validates_inclusion_of :age, in: 0..99
-
# end
-
#
-
# Person.validators_on(:name)
-
# # => [
-
# # #<ActiveModel::Validations::PresenceValidator:0x007fe604914e60 @attributes=[:name], @options={}>,
-
# # #<ActiveModel::Validations::InclusionValidator:0x007fe603bb8780 @attributes=[:age], @options={in:0..99}>
-
# # ]
-
1
def validators_on(*attributes)
-
2
attributes.flat_map do |attribute|
-
2
_validators[attribute.to_sym]
-
end
-
end
-
-
# Returns +true+ if +attribute+ is an attribute method, +false+ otherwise.
-
#
-
# class Person
-
# include ActiveModel::Validations
-
#
-
# attr_accessor :name
-
# end
-
#
-
# User.attribute_method?(:name) # => true
-
# User.attribute_method?(:age) # => false
-
1
def attribute_method?(attribute)
-
4
method_defined?(attribute)
-
end
-
-
# Copy validators on inheritance.
-
1
def inherited(base) #:nodoc:
-
486
dup = _validators.dup
-
540
base._validators = dup.each { |k, v| dup[k] = v.dup }
-
486
super
-
end
-
end
-
-
# Clean the +Errors+ object if instance is duped.
-
1
def initialize_dup(other) #:nodoc:
-
25
@errors = nil
-
25
super
-
end
-
-
# Returns the +Errors+ object that holds all information about attribute
-
# error messages.
-
#
-
# class Person
-
# include ActiveModel::Validations
-
#
-
# attr_accessor :name
-
# validates_presence_of :name
-
# end
-
#
-
# person = Person.new
-
# person.valid? # => false
-
# person.errors # => #<ActiveModel::Errors:0x007fe603816640 @messages={name:["can't be blank"]}>
-
1
def errors
-
12106
@errors ||= Errors.new(self)
-
end
-
-
# Runs all the specified validations and returns +true+ if no errors were
-
# added otherwise +false+.
-
#
-
# class Person
-
# include ActiveModel::Validations
-
#
-
# attr_accessor :name
-
# validates_presence_of :name
-
# end
-
#
-
# person = Person.new
-
# person.name = ''
-
# person.valid? # => false
-
# person.name = 'david'
-
# person.valid? # => true
-
#
-
# Context can optionally be supplied to define which callbacks to test
-
# against (the context is defined on the validations using <tt>:on</tt>).
-
#
-
# class Person
-
# include ActiveModel::Validations
-
#
-
# attr_accessor :name
-
# validates_presence_of :name, on: :new
-
# end
-
#
-
# person = Person.new
-
# person.valid? # => true
-
# person.valid?(:new) # => false
-
1
def valid?(context = nil)
-
3407
current_context, self.validation_context = validation_context, context
-
3407
errors.clear
-
3407
run_validations!
-
ensure
-
3407
self.validation_context = current_context
-
end
-
-
# Performs the opposite of <tt>valid?</tt>. Returns +true+ if errors were
-
# added, +false+ otherwise.
-
#
-
# class Person
-
# include ActiveModel::Validations
-
#
-
# attr_accessor :name
-
# validates_presence_of :name
-
# end
-
#
-
# person = Person.new
-
# person.name = ''
-
# person.invalid? # => true
-
# person.name = 'david'
-
# person.invalid? # => false
-
#
-
# Context can optionally be supplied to define which callbacks to test
-
# against (the context is defined on the validations using <tt>:on</tt>).
-
#
-
# class Person
-
# include ActiveModel::Validations
-
#
-
# attr_accessor :name
-
# validates_presence_of :name, on: :new
-
# end
-
#
-
# person = Person.new
-
# person.invalid? # => false
-
# person.invalid?(:new) # => true
-
1
def invalid?(context = nil)
-
12
!valid?(context)
-
end
-
-
# Hook method defining how an attribute value should be retrieved. By default
-
# this is assumed to be an instance named after the attribute. Override this
-
# method in subclasses should you need to retrieve the value for a given
-
# attribute differently:
-
#
-
# class MyClass
-
# include ActiveModel::Validations
-
#
-
# def initialize(data = {})
-
# @data = data
-
# end
-
#
-
# def read_attribute_for_validation(key)
-
# @data[key]
-
# end
-
# end
-
1
alias :read_attribute_for_validation :send
-
-
1
protected
-
-
1
def run_validations! #:nodoc:
-
3402
run_callbacks :validate
-
3402
errors.empty?
-
end
-
end
-
end
-
-
1
Dir[File.dirname(__FILE__) + "/validations/*.rb"].sort.each do |path|
-
12
filename = File.basename(path)
-
12
require "active_model/validations/#{filename}"
-
end
-
1
module ActiveModel
-
-
1
module Validations
-
1
class AcceptanceValidator < EachValidator # :nodoc:
-
1
def initialize(options)
-
2
super({ :allow_nil => true, :accept => "1" }.merge!(options))
-
end
-
-
1
def validate_each(record, attribute, value)
-
1
unless value == options[:accept]
-
1
record.errors.add(attribute, :accepted, options.except(:accept, :allow_nil))
-
end
-
end
-
-
1
def setup(klass)
-
4
attr_readers = attributes.reject { |name| klass.attribute_method?(name) }
-
4
attr_writers = attributes.reject { |name| klass.attribute_method?("#{name}=") }
-
2
klass.send(:attr_reader, *attr_readers)
-
2
klass.send(:attr_writer, *attr_writers)
-
end
-
end
-
-
1
module HelperMethods
-
# Encapsulates the pattern of wanting to validate the acceptance of a
-
# terms of service check box (or similar agreement).
-
#
-
# class Person < ActiveRecord::Base
-
# validates_acceptance_of :terms_of_service
-
# validates_acceptance_of :eula, message: 'must be abided'
-
# end
-
#
-
# If the database column does not exist, the +terms_of_service+ attribute
-
# is entirely virtual. This check is performed only if +terms_of_service+
-
# is not +nil+ and by default on save.
-
#
-
# Configuration options:
-
# * <tt>:message</tt> - A custom error message (default is: "must be
-
# accepted").
-
# * <tt>:allow_nil</tt> - Skip validation if attribute is +nil+ (default
-
# is +true+).
-
# * <tt>:accept</tt> - Specifies value that is considered accepted.
-
# The default value is a string "1", which makes it easy to relate to
-
# an HTML checkbox. This should be set to +true+ if you are validating
-
# a database column, since the attribute is typecast from "1" to +true+
-
# before validation.
-
#
-
# There is also a list of default options supported by every validator:
-
# +:if+, +:unless+, +:on+ and +:strict+.
-
# See <tt>ActiveModel::Validation#validates</tt> for more information
-
1
def validates_acceptance_of(*attr_names)
-
2
validates_with AcceptanceValidator, _merge_attributes(attr_names)
-
end
-
end
-
end
-
end
-
1
require 'active_support/callbacks'
-
-
1
module ActiveModel
-
1
module Validations
-
# == Active \Model Validation Callbacks
-
#
-
# Provides an interface for any class to have +before_validation+ and
-
# +after_validation+ callbacks.
-
#
-
# First, include ActiveModel::Validations::Callbacks from the class you are
-
# creating:
-
#
-
# class MyModel
-
# include ActiveModel::Validations::Callbacks
-
#
-
# before_validation :do_stuff_before_validation
-
# after_validation :do_stuff_after_validation
-
# end
-
#
-
# Like other <tt>before_*</tt> callbacks if +before_validation+ returns
-
# +false+ then <tt>valid?</tt> will not be called.
-
1
module Callbacks
-
1
extend ActiveSupport::Concern
-
-
1
included do
-
1
include ActiveSupport::Callbacks
-
1
define_callbacks :validation, :terminator => "result == false", :skip_after_callbacks_if_terminated => true, :scope => [:kind, :name]
-
end
-
-
1
module ClassMethods
-
# Defines a callback that will get called right before validation
-
# happens.
-
#
-
# class Person
-
# include ActiveModel::Validations
-
# include ActiveModel::Validations::Callbacks
-
#
-
# attr_accessor :name
-
#
-
# validates_length_of :name, maximum: 6
-
#
-
# before_validation :remove_whitespaces
-
#
-
# private
-
#
-
# def remove_whitespaces
-
# name.strip!
-
# end
-
# end
-
#
-
# person = Person.new
-
# person.name = ' bob '
-
# person.valid? # => true
-
# person.name # => "bob"
-
1
def before_validation(*args, &block)
-
15
options = args.last
-
15
if options.is_a?(Hash) && options[:on]
-
3
options[:if] = Array(options[:if])
-
3
options[:on] = Array(options[:on])
-
3
options[:if].unshift("#{options[:on]}.include? self.validation_context")
-
end
-
15
set_callback(:validation, :before, *args, &block)
-
end
-
-
# Defines a callback that will get called right after validation
-
# happens.
-
#
-
# class Person
-
# include ActiveModel::Validations
-
# include ActiveModel::Validations::Callbacks
-
#
-
# attr_accessor :name, :status
-
#
-
# validates_presence_of :name
-
#
-
# after_validation :set_status
-
#
-
# private
-
#
-
# def set_status
-
# self.status = errors.empty?
-
# end
-
# end
-
#
-
# person = Person.new
-
# person.name = ''
-
# person.valid? # => false
-
# person.status # => false
-
# person.name = 'bob'
-
# person.valid? # => true
-
# person.status # => true
-
1
def after_validation(*args, &block)
-
12
options = args.extract_options!
-
12
options[:prepend] = true
-
12
options[:if] = Array(options[:if])
-
12
if options[:on]
-
3
options[:on] = Array(options[:on])
-
3
options[:if].unshift("#{options[:on]}.include? self.validation_context")
-
end
-
12
set_callback(:validation, :after, *(args << options), &block)
-
end
-
end
-
-
1
protected
-
-
# Overwrite run validations to include callbacks.
-
1
def run_validations! #:nodoc:
-
6809
run_callbacks(:validation) { super }
-
end
-
end
-
end
-
end
-
1
require 'active_support/core_ext/range'
-
-
1
module ActiveModel
-
1
module Validations
-
1
module Clusivity #:nodoc:
-
1
ERROR_MESSAGE = "An object with the method #include? or a proc, lambda or symbol is required, " <<
-
"and must be supplied as the :in (or :within) option of the configuration hash"
-
-
1
def check_validity!
-
3
unless delimiter.respond_to?(:include?) || delimiter.respond_to?(:call) || delimiter.respond_to?(:to_sym)
-
raise ArgumentError, ERROR_MESSAGE
-
end
-
end
-
-
1
private
-
-
1
def include?(record, value)
-
74
exclusions = if delimiter.respond_to?(:call)
-
delimiter.call(record)
-
elsif delimiter.respond_to?(:to_sym)
-
record.send(delimiter)
-
else
-
74
delimiter
-
end
-
-
74
exclusions.send(inclusion_method(exclusions), value)
-
end
-
-
1
def delimiter
-
225
@delimiter ||= options[:in] || options[:within]
-
end
-
-
# In Ruby 1.9 <tt>Range#include?</tt> on non-numeric ranges checks all possible values in the
-
# range for equality, so it may be slow for large ranges. The new <tt>Range#cover?</tt>
-
# uses the previous logic of comparing a value with the range endpoints.
-
1
def inclusion_method(enumerable)
-
74
enumerable.is_a?(Range) ? :cover? : :include?
-
end
-
end
-
end
-
end
-
1
module ActiveModel
-
-
1
module Validations
-
1
class ConfirmationValidator < EachValidator # :nodoc:
-
1
def validate_each(record, attribute, value)
-
if (confirmed = record.send("#{attribute}_confirmation")) && (value != confirmed)
-
human_attribute_name = record.class.human_attribute_name(attribute)
-
record.errors.add(:"#{attribute}_confirmation", :confirmation, options.merge(:attribute => human_attribute_name))
-
end
-
end
-
-
1
def setup(klass)
-
klass.send(:attr_accessor, *attributes.map do |attribute|
-
:"#{attribute}_confirmation" unless klass.method_defined?(:"#{attribute}_confirmation")
-
end.compact)
-
end
-
end
-
-
1
module HelperMethods
-
# Encapsulates the pattern of wanting to validate a password or email
-
# address field with a confirmation.
-
#
-
# Model:
-
# class Person < ActiveRecord::Base
-
# validates_confirmation_of :user_name, :password
-
# validates_confirmation_of :email_address,
-
# message: 'should match confirmation'
-
# end
-
#
-
# View:
-
# <%= password_field "person", "password" %>
-
# <%= password_field "person", "password_confirmation" %>
-
#
-
# The added +password_confirmation+ attribute is virtual; it exists only
-
# as an in-memory attribute for validating the password. To achieve this,
-
# the validation adds accessors to the model for the confirmation
-
# attribute.
-
#
-
# NOTE: This check is performed only if +password_confirmation+ is not
-
# +nil+. To require confirmation, make sure to add a presence check for
-
# the confirmation attribute:
-
#
-
# validates_presence_of :password_confirmation, if: :password_changed?
-
#
-
# Configuration options:
-
# * <tt>:message</tt> - A custom error message (default is: "doesn't match
-
# confirmation").
-
#
-
# There is also a list of default options supported by every validator:
-
# +:if+, +:unless+, +:on+ and +:strict+.
-
# See <tt>ActiveModel::Validation#validates</tt> for more information
-
1
def validates_confirmation_of(*attr_names)
-
validates_with ConfirmationValidator, _merge_attributes(attr_names)
-
end
-
end
-
end
-
end
-
1
require "active_model/validations/clusivity"
-
-
1
module ActiveModel
-
-
1
module Validations
-
1
class ExclusionValidator < EachValidator # :nodoc:
-
1
include Clusivity
-
-
1
def validate_each(record, attribute, value)
-
if include?(record, value)
-
record.errors.add(attribute, :exclusion, options.except(:in, :within).merge!(:value => value))
-
end
-
end
-
end
-
-
1
module HelperMethods
-
# Validates that the value of the specified attribute is not in a
-
# particular enumerable object.
-
#
-
# class Person < ActiveRecord::Base
-
# validates_exclusion_of :username, in: %w( admin superuser ), message: "You don't belong here"
-
# validates_exclusion_of :age, in: 30..60, message: 'This site is only for under 30 and over 60'
-
# validates_exclusion_of :format, in: %w( mov avi ), message: "extension %{value} is not allowed"
-
# validates_exclusion_of :password, in: ->(person) { [person.username, person.first_name] },
-
# message: 'should not be the same as your username or first name'
-
# validates_exclusion_of :karma, in: :reserved_karmas
-
# end
-
#
-
# Configuration options:
-
# * <tt>:in</tt> - An enumerable object of items that the value shouldn't
-
# be part of. This can be supplied as a proc, lambda or symbol which returns an
-
# enumerable. If the enumerable is a range the test is performed with
-
# * <tt>:within</tt> - A synonym(or alias) for <tt>:in</tt>
-
# <tt>Range#cover?</tt>, otherwise with <tt>include?</tt>.
-
# * <tt>:message</tt> - Specifies a custom error message (default is: "is
-
# reserved").
-
# * <tt>:allow_nil</tt> - If set to true, skips this validation if the
-
# attribute is +nil+ (default is +false+).
-
# * <tt>:allow_blank</tt> - If set to true, skips this validation if the
-
# attribute is blank(default is +false+).
-
#
-
# There is also a list of default options supported by every validator:
-
# +:if+, +:unless+, +:on+ and +:strict+.
-
# See <tt>ActiveModel::Validation#validates</tt> for more information
-
1
def validates_exclusion_of(*attr_names)
-
validates_with ExclusionValidator, _merge_attributes(attr_names)
-
end
-
end
-
end
-
end
-
1
module ActiveModel
-
-
1
module Validations
-
1
class FormatValidator < EachValidator # :nodoc:
-
1
def validate_each(record, attribute, value)
-
188
if options[:with]
-
188
regexp = option_call(record, :with)
-
188
record_error(record, attribute, :with, value) if value.to_s !~ regexp
-
elsif options[:without]
-
regexp = option_call(record, :without)
-
record_error(record, attribute, :without, value) if value.to_s =~ regexp
-
end
-
end
-
-
1
def check_validity!
-
1
unless options.include?(:with) ^ options.include?(:without) # ^ == xor, or "exclusive or"
-
raise ArgumentError, "Either :with or :without must be supplied (but not both)"
-
end
-
-
1
check_options_validity(options, :with)
-
1
check_options_validity(options, :without)
-
end
-
-
1
private
-
-
1
def option_call(record, name)
-
188
option = options[name]
-
188
option.respond_to?(:call) ? option.call(record) : option
-
end
-
-
1
def record_error(record, attribute, name, value)
-
4
record.errors.add(attribute, :invalid, options.except(name).merge!(:value => value))
-
end
-
-
1
def regexp_using_multiline_anchors?(regexp)
-
regexp.source.start_with?("^") ||
-
1
(regexp.source.end_with?("$") && !regexp.source.end_with?("\\$"))
-
end
-
-
1
def check_options_validity(options, name)
-
2
option = options[name]
-
2
if option && !option.is_a?(Regexp) && !option.respond_to?(:call)
-
raise ArgumentError, "A regular expression or a proc or lambda must be supplied as :#{name}"
-
2
elsif option && option.is_a?(Regexp) &&
-
regexp_using_multiline_anchors?(option) && options[:multiline] != true
-
raise ArgumentError, "The provided regular expression is using multiline anchors (^ or $), " \
-
"which may present a security risk. Did you mean to use \\A and \\z, or forgot to add the " \
-
":multiline => true option?"
-
end
-
end
-
end
-
-
1
module HelperMethods
-
# Validates whether the value of the specified attribute is of the correct
-
# form, going by the regular expression provided.You can require that the
-
# attribute matches the regular expression:
-
#
-
# class Person < ActiveRecord::Base
-
# validates_format_of :email, with: /\A([^@\s]+)@((?:[-a-z0-9]+\.)+[a-z]{2,})\z/i, on: :create
-
# end
-
#
-
# Alternatively, you can require that the specified attribute does _not_
-
# match the regular expression:
-
#
-
# class Person < ActiveRecord::Base
-
# validates_format_of :email, without: /NOSPAM/
-
# end
-
#
-
# You can also provide a proc or lambda which will determine the regular
-
# expression that will be used to validate the attribute.
-
#
-
# class Person < ActiveRecord::Base
-
# # Admin can have number as a first letter in their screen name
-
# validates_format_of :screen_name,
-
# with: ->(person) { person.admin? ? /\A[a-z0-9][a-z0-9_\-]*\z/i : /\A[a-z][a-z0-9_\-]*\z/i }
-
# end
-
#
-
# Note: use <tt>\A</tt> and <tt>\Z</tt> to match the start and end of the
-
# string, <tt>^</tt> and <tt>$</tt> match the start/end of a line.
-
#
-
# Due to frequent misuse of <tt>^</tt> and <tt>$</tt>, you need to pass
-
# the <tt>multiline: true</tt> option in case you use any of these two
-
# anchors in the provided regular expression. In most cases, you should be
-
# using <tt>\A</tt> and <tt>\z</tt>.
-
#
-
# You must pass either <tt>:with</tt> or <tt>:without</tt> as an option.
-
# In addition, both must be a regular expression or a proc or lambda, or
-
# else an exception will be raised.
-
#
-
# Configuration options:
-
# * <tt>:message</tt> - A custom error message (default is: "is invalid").
-
# * <tt>:allow_nil</tt> - If set to true, skips this validation if the
-
# attribute is +nil+ (default is +false+).
-
# * <tt>:allow_blank</tt> - If set to true, skips this validation if the
-
# attribute is blank (default is +false+).
-
# * <tt>:with</tt> - Regular expression that if the attribute matches will
-
# result in a successful validation. This can be provided as a proc or
-
# lambda returning regular expression which will be called at runtime.
-
# * <tt>:without</tt> - Regular expression that if the attribute does not
-
# match will result in a successful validation. This can be provided as
-
# a proc or lambda returning regular expression which will be called at
-
# runtime.
-
# * <tt>:multiline</tt> - Set to true if your regular expression contains
-
# anchors that match the beginning or end of lines as opposed to the
-
# beginning or end of the string. These anchors are <tt>^</tt> and <tt>$</tt>.
-
#
-
# There is also a list of default options supported by every validator:
-
# +:if+, +:unless+, +:on+ and +:strict+.
-
# See <tt>ActiveModel::Validation#validates</tt> for more information
-
1
def validates_format_of(*attr_names)
-
1
validates_with FormatValidator, _merge_attributes(attr_names)
-
end
-
end
-
end
-
end
-
1
require "active_model/validations/clusivity"
-
-
1
module ActiveModel
-
-
1
module Validations
-
1
class InclusionValidator < EachValidator # :nodoc:
-
1
include Clusivity
-
-
1
def validate_each(record, attribute, value)
-
74
unless include?(record, value)
-
5
record.errors.add(attribute, :inclusion, options.except(:in, :within).merge!(:value => value))
-
end
-
end
-
end
-
-
1
module HelperMethods
-
# Validates whether the value of the specified attribute is available in a
-
# particular enumerable object.
-
#
-
# class Person < ActiveRecord::Base
-
# validates_inclusion_of :gender, in: %w( m f )
-
# validates_inclusion_of :age, in: 0..99
-
# validates_inclusion_of :format, in: %w( jpg gif png ), message: "extension %{value} is not included in the list"
-
# validates_inclusion_of :states, in: ->(person) { STATES[person.country] }
-
# validates_inclusion_of :karma, in: :available_karmas
-
# end
-
#
-
# Configuration options:
-
# * <tt>:in</tt> - An enumerable object of available items. This can be
-
# supplied as a proc, lambda or symbol which returns an enumerable. If the
-
# enumerable is a range the test is performed with <tt>Range#cover?</tt>,
-
# otherwise with <tt>include?</tt>.
-
# * <tt>:within</tt> - A synonym(or alias) for <tt>:in</tt>
-
# * <tt>:message</tt> - Specifies a custom error message (default is: "is
-
# not included in the list").
-
# * <tt>:allow_nil</tt> - If set to +true+, skips this validation if the
-
# attribute is +nil+ (default is +false+).
-
# * <tt>:allow_blank</tt> - If set to +true+, skips this validation if the
-
# attribute is blank (default is +false+).
-
#
-
# There is also a list of default options supported by every validator:
-
# +:if+, +:unless+, +:on+ and +:strict+.
-
# See <tt>ActiveModel::Validation#validates</tt> for more information
-
1
def validates_inclusion_of(*attr_names)
-
3
validates_with InclusionValidator, _merge_attributes(attr_names)
-
end
-
end
-
end
-
end
-
1
module ActiveModel
-
-
# == Active \Model Length \Validator
-
1
module Validations
-
1
class LengthValidator < EachValidator # :nodoc:
-
1
MESSAGES = { :is => :wrong_length, :minimum => :too_short, :maximum => :too_long }.freeze
-
1
CHECKS = { :is => :==, :minimum => :>=, :maximum => :<= }.freeze
-
-
1
RESERVED_OPTIONS = [:minimum, :maximum, :within, :is, :tokenizer, :too_short, :too_long]
-
-
1
def initialize(options)
-
5
if range = (options.delete(:in) || options.delete(:within))
-
3
raise ArgumentError, ":in and :within must be a Range" unless range.is_a?(Range)
-
3
options[:minimum], options[:maximum] = range.min, range.max
-
end
-
-
5
super
-
end
-
-
1
def check_validity!
-
5
keys = CHECKS.keys & options.keys
-
-
5
if keys.empty?
-
raise ArgumentError, 'Range unspecified. Specify the :in, :within, :maximum, :minimum, or :is option.'
-
end
-
-
5
keys.each do |key|
-
8
value = options[key]
-
-
8
unless (value.is_a?(Integer) && value >= 0) || value == Float::INFINITY
-
raise ArgumentError, ":#{key} must be a nonnegative Integer or Infinity"
-
end
-
end
-
end
-
-
1
def validate_each(record, attribute, value)
-
76
value = tokenize(value)
-
76
value_length = value.respond_to?(:length) ? value.length : value.to_s.length
-
76
errors_options = options.except(*RESERVED_OPTIONS)
-
-
76
CHECKS.each do |key, validity_check|
-
228
next unless check_value = options[key]
-
148
next if value_length.send(validity_check, check_value)
-
-
13
errors_options[:count] = check_value
-
-
13
default_message = options[MESSAGES[key]]
-
13
errors_options[:message] ||= default_message if default_message
-
-
13
record.errors.add(attribute, MESSAGES[key], errors_options)
-
end
-
end
-
-
1
private
-
-
1
def tokenize(value)
-
if options[:tokenizer] && value.kind_of?(String)
-
options[:tokenizer].call(value)
-
76
end || value
-
end
-
end
-
-
1
module HelperMethods
-
-
# Validates that the specified attribute matches the length restrictions
-
# supplied. Only one option can be used at a time:
-
#
-
# class Person < ActiveRecord::Base
-
# validates_length_of :first_name, maximum: 30
-
# validates_length_of :last_name, maximum: 30, message: "less than 30 if you don't mind"
-
# validates_length_of :fax, in: 7..32, allow_nil: true
-
# validates_length_of :phone, in: 7..32, allow_blank: true
-
# validates_length_of :user_name, within: 6..20, too_long: 'pick a shorter name', too_short: 'pick a longer name'
-
# validates_length_of :zip_code, minimum: 5, too_short: 'please enter at least 5 characters'
-
# validates_length_of :smurf_leader, is: 4, message: "papa is spelled with 4 characters... don't play me."
-
# validates_length_of :essay, minimum: 100, too_short: 'Your essay must be at least 100 words.',
-
# tokenizer: ->(str) { str.scan(/\w+/) }
-
# end
-
#
-
# Configuration options:
-
# * <tt>:minimum</tt> - The minimum size of the attribute.
-
# * <tt>:maximum</tt> - The maximum size of the attribute.
-
# * <tt>:is</tt> - The exact size of the attribute.
-
# * <tt>:within</tt> - A range specifying the minimum and maximum size of
-
# the attribute.
-
# * <tt>:in</tt> - A synonym (or alias) for <tt>:within</tt>.
-
# * <tt>:allow_nil</tt> - Attribute may be +nil+; skip validation.
-
# * <tt>:allow_blank</tt> - Attribute may be blank; skip validation.
-
# * <tt>:too_long</tt> - The error message if the attribute goes over the
-
# maximum (default is: "is too long (maximum is %{count} characters)").
-
# * <tt>:too_short</tt> - The error message if the attribute goes under the
-
# minimum (default is: "is too short (min is %{count} characters)").
-
# * <tt>:wrong_length</tt> - The error message if using the <tt>:is</tt>
-
# method and the attribute is the wrong size (default is: "is the wrong
-
# length (should be %{count} characters)").
-
# * <tt>:message</tt> - The error message to use for a <tt>:minimum</tt>,
-
# <tt>:maximum</tt>, or <tt>:is</tt> violation. An alias of the appropriate
-
# <tt>too_long</tt>/<tt>too_short</tt>/<tt>wrong_length</tt> message.
-
# * <tt>:tokenizer</tt> - Specifies how to split up the attribute string.
-
# (e.g. <tt>tokenizer: ->(str) { str.scan(/\w+/) }</tt> to count words
-
# as in above example). Defaults to <tt>->(value) { value.split(//) }</tt>
-
# which counts individual characters.
-
#
-
# There is also a list of default options supported by every validator:
-
# +:if+, +:unless+, +:on+ and +:strict+.
-
# See <tt>ActiveModel::Validation#validates</tt> for more information
-
1
def validates_length_of(*attr_names)
-
5
validates_with LengthValidator, _merge_attributes(attr_names)
-
end
-
-
1
alias_method :validates_size_of, :validates_length_of
-
end
-
end
-
end
-
1
module ActiveModel
-
-
1
module Validations
-
1
class NumericalityValidator < EachValidator # :nodoc:
-
1
CHECKS = { :greater_than => :>, :greater_than_or_equal_to => :>=,
-
:equal_to => :==, :less_than => :<, :less_than_or_equal_to => :<=,
-
:odd => :odd?, :even => :even?, :other_than => :!= }.freeze
-
-
1
RESERVED_OPTIONS = CHECKS.keys + [:only_integer]
-
-
1
def check_validity!
-
2
keys = CHECKS.keys - [:odd, :even]
-
2
options.slice(*keys).each do |option, value|
-
next if value.is_a?(Numeric) || value.is_a?(Proc) || value.is_a?(Symbol)
-
raise ArgumentError, ":#{option} must be a number, a symbol or a proc"
-
end
-
end
-
-
1
def validate_each(record, attr_name, value)
-
6
before_type_cast = "#{attr_name}_before_type_cast"
-
-
6
raw_value = record.send(before_type_cast) if record.respond_to?(before_type_cast.to_sym)
-
6
raw_value ||= value
-
-
6
return if options[:allow_nil] && raw_value.nil?
-
-
6
unless value = parse_raw_value_as_a_number(raw_value)
-
2
record.errors.add(attr_name, :not_a_number, filtered_options(raw_value))
-
2
return
-
end
-
-
4
if options[:only_integer]
-
unless value = parse_raw_value_as_an_integer(raw_value)
-
record.errors.add(attr_name, :not_an_integer, filtered_options(raw_value))
-
return
-
end
-
end
-
-
4
options.slice(*CHECKS.keys).each do |option, option_value|
-
case option
-
when :odd, :even
-
unless value.to_i.send(CHECKS[option])
-
record.errors.add(attr_name, option, filtered_options(value))
-
end
-
else
-
option_value = option_value.call(record) if option_value.is_a?(Proc)
-
option_value = record.send(option_value) if option_value.is_a?(Symbol)
-
-
unless value.send(CHECKS[option], option_value)
-
record.errors.add(attr_name, option, filtered_options(value).merge(:count => option_value))
-
end
-
end
-
end
-
end
-
-
1
protected
-
-
1
def parse_raw_value_as_a_number(raw_value)
-
6
case raw_value
-
when /\A0[xX]/
-
nil
-
else
-
6
begin
-
6
Kernel.Float(raw_value)
-
2
rescue ArgumentError, TypeError
-
2
nil
-
end
-
end
-
end
-
-
1
def parse_raw_value_as_an_integer(raw_value)
-
raw_value.to_i if raw_value.to_s =~ /\A[+-]?\d+\Z/
-
end
-
-
1
def filtered_options(value)
-
2
options.except(*RESERVED_OPTIONS).merge!(:value => value)
-
end
-
end
-
-
1
module HelperMethods
-
# Validates whether the value of the specified attribute is numeric by
-
# trying to convert it to a float with Kernel.Float (if <tt>only_integer</tt>
-
# is +false+) or applying it to the regular expression <tt>/\A[\+\-]?\d+\Z/</tt>
-
# (if <tt>only_integer</tt> is set to +true+).
-
#
-
# class Person < ActiveRecord::Base
-
# validates_numericality_of :value, on: :create
-
# end
-
#
-
# Configuration options:
-
# * <tt>:message</tt> - A custom error message (default is: "is not a number").
-
# * <tt>:only_integer</tt> - Specifies whether the value has to be an
-
# integer, e.g. an integral value (default is +false+).
-
# * <tt>:allow_nil</tt> - Skip validation if attribute is +nil+ (default is
-
# +false+). Notice that for fixnum and float columns empty strings are
-
# converted to +nil+.
-
# * <tt>:greater_than</tt> - Specifies the value must be greater than the
-
# supplied value.
-
# * <tt>:greater_than_or_equal_to</tt> - Specifies the value must be
-
# greater than or equal the supplied value.
-
# * <tt>:equal_to</tt> - Specifies the value must be equal to the supplied
-
# value.
-
# * <tt>:less_than</tt> - Specifies the value must be less than the
-
# supplied value.
-
# * <tt>:less_than_or_equal_to</tt> - Specifies the value must be less
-
# than or equal the supplied value.
-
# * <tt>:other_than</tt> - Specifies the value must be other than the
-
# supplied value.
-
# * <tt>:odd</tt> - Specifies the value must be an odd number.
-
# * <tt>:even</tt> - Specifies the value must be an even number.
-
#
-
# There is also a list of default options supported by every validator:
-
# +:if+, +:unless+, +:on+ and +:strict+ .
-
# See <tt>ActiveModel::Validation#validates</tt> for more information
-
#
-
# The following checks can also be supplied with a proc or a symbol which
-
# corresponds to a method:
-
#
-
# * <tt>:greater_than</tt>
-
# * <tt>:greater_than_or_equal_to</tt>
-
# * <tt>:equal_to</tt>
-
# * <tt>:less_than</tt>
-
# * <tt>:less_than_or_equal_to</tt>
-
#
-
# For example:
-
#
-
# class Person < ActiveRecord::Base
-
# validates_numericality_of :width, less_than: ->(person) { person.height }
-
# validates_numericality_of :width, greater_than: :minimum_weight
-
# end
-
1
def validates_numericality_of(*attr_names)
-
2
validates_with NumericalityValidator, _merge_attributes(attr_names)
-
end
-
end
-
end
-
end
-
-
1
module ActiveModel
-
-
1
module Validations
-
1
class PresenceValidator < EachValidator # :nodoc:
-
1
def validate(record)
-
1388
record.errors.add_on_blank(attributes, options)
-
end
-
end
-
-
1
module HelperMethods
-
# Validates that the specified attributes are not blank (as defined by
-
# Object#blank?). Happens by default on save.
-
#
-
# class Person < ActiveRecord::Base
-
# validates_presence_of :first_name
-
# end
-
#
-
# The first_name attribute must be in the object and it cannot be blank.
-
#
-
# If you want to validate the presence of a boolean field (where the real
-
# values are +true+ and +false+), you will want to use
-
# <tt>validates_inclusion_of :field_name, in: [true, false]</tt>.
-
#
-
# This is due to the way Object#blank? handles boolean values:
-
# <tt>false.blank? # => true</tt>.
-
#
-
# Configuration options:
-
# * <tt>:message</tt> - A custom error message (default is: "can't be blank").
-
#
-
# There is also a list of default options supported by every validator:
-
# +:if+, +:unless+, +:on+ and +:strict+.
-
# See <tt>ActiveModel::Validation#validates</tt> for more information
-
1
def validates_presence_of(*attr_names)
-
validates_with PresenceValidator, _merge_attributes(attr_names)
-
end
-
end
-
end
-
end
-
1
require 'active_support/core_ext/hash/slice'
-
-
1
module ActiveModel
-
1
module Validations
-
1
module ClassMethods
-
# This method is a shortcut to all default validators and any custom
-
# validator classes ending in 'Validator'. Note that Rails default
-
# validators can be overridden inside specific classes by creating
-
# custom validator classes in their place such as PresenceValidator.
-
#
-
# Examples of using the default rails validators:
-
#
-
# validates :terms, acceptance: true
-
# validates :password, confirmation: true
-
# validates :username, exclusion: { in: %w(admin superuser) }
-
# validates :email, format: { with: /\A([^@\s]+)@((?:[-a-z0-9]+\.)+[a-z]{2,})\Z/i, on: :create }
-
# validates :age, inclusion: { in: 0..9 }
-
# validates :first_name, length: { maximum: 30 }
-
# validates :age, numericality: true
-
# validates :username, presence: true
-
# validates :username, uniqueness: true
-
#
-
# The power of the +validates+ method comes when using custom validators
-
# and default validators in one call for a given attribute.
-
#
-
# class EmailValidator < ActiveModel::EachValidator
-
# def validate_each(record, attribute, value)
-
# record.errors.add attribute, (options[:message] || "is not an email") unless
-
# value =~ /\A([^@\s]+)@((?:[-a-z0-9]+\.)+[a-z]{2,})\z/i
-
# end
-
# end
-
#
-
# class Person
-
# include ActiveModel::Validations
-
# attr_accessor :name, :email
-
#
-
# validates :name, presence: true, uniqueness: true, length: { maximum: 100 }
-
# validates :email, presence: true, email: true
-
# end
-
#
-
# Validator classes may also exist within the class being validated
-
# allowing custom modules of validators to be included as needed.
-
#
-
# class Film
-
# include ActiveModel::Validations
-
#
-
# class TitleValidator < ActiveModel::EachValidator
-
# def validate_each(record, attribute, value)
-
# record.errors.add attribute, "must start with 'the'" unless value =~ /\Athe/i
-
# end
-
# end
-
#
-
# validates :name, title: true
-
# end
-
#
-
# Additionally validator classes may be in another namespace and still
-
# used within any class.
-
#
-
# validates :name, :'film/title' => true
-
#
-
# The validators hash can also handle regular expressions, ranges, arrays
-
# and strings in shortcut form.
-
#
-
# validates :email, format: /@/
-
# validates :gender, inclusion: %w(male female)
-
# validates :password, length: 6..20
-
#
-
# When using shortcut form, ranges and arrays are passed to your
-
# validator's initializer as <tt>options[:in]</tt> while other types
-
# including regular expressions and strings are passed as <tt>options[:with]</tt>.
-
#
-
# There is also a list of options that could be used along with validators:
-
#
-
# * <tt>:on</tt> - Specifies when this validation is active. Runs in all
-
# validation contexts by default (+nil+), other options are <tt>:create</tt>
-
# and <tt>:update</tt>.
-
# * <tt>:if</tt> - Specifies a method, proc or string to call to determine
-
# if the validation should occur (e.g. <tt>if: :allow_validation</tt>,
-
# or <tt>if: Proc.new { |user| user.signup_step > 2 }</tt>). The method,
-
# proc or string should return or evaluate to a +true+ or +false+ value.
-
# * <tt>:unless</tt> - Specifies a method, proc or string to call to determine
-
# if the validation should not occur (e.g. <tt>unless: :skip_validation</tt>,
-
# or <tt>unless: Proc.new { |user| user.signup_step <= 2 }</tt>). The
-
# method, proc or string should return or evaluate to a +true+ or
-
# +false+ value.
-
# * <tt>:strict</tt> - if the <tt>:strict</tt> option is set to true
-
# will raise ActiveModel::StrictValidationFailed instead of adding the error.
-
# <tt>:strict</tt> option can also be set to any other exception.
-
#
-
# Example:
-
#
-
# validates :password, presence: true, confirmation: true, if: :password_required?
-
# validates :token, uniqueness: true, strict: TokenGenerationException
-
#
-
#
-
# Finally, the options +:if+, +:unless+, +:on+, +:allow_blank+, +:allow_nil+, +:strict+
-
# and +:message+ can be given to one specific validator, as a hash:
-
#
-
# validates :password, presence: { if: :password_required?, message: 'is forgotten.' }, confirmation: true
-
1
def validates(*attributes)
-
2
defaults = attributes.extract_options!.dup
-
2
validations = defaults.slice!(*_validates_default_keys)
-
-
2
raise ArgumentError, "You need to supply at least one attribute" if attributes.empty?
-
2
raise ArgumentError, "You need to supply at least one validation" if validations.empty?
-
-
2
defaults[:attributes] = attributes
-
-
2
validations.each do |key, options|
-
2
next unless options
-
2
key = "#{key.to_s.camelize}Validator"
-
-
2
begin
-
2
validator = key.include?('::') ? key.constantize : const_get(key)
-
rescue NameError
-
raise ArgumentError, "Unknown validator: '#{key}'"
-
end
-
-
2
validates_with(validator, defaults.merge(_parse_validates_options(options)))
-
end
-
end
-
-
# This method is used to define validations that cannot be corrected by end
-
# users and are considered exceptional. So each validator defined with bang
-
# or <tt>:strict</tt> option set to <tt>true</tt> will always raise
-
# <tt>ActiveModel::StrictValidationFailed</tt> instead of adding error
-
# when validation fails. See <tt>validates</tt> for more information about
-
# the validation itself.
-
#
-
# class Person
-
# include ActiveModel::Validations
-
#
-
# attr_accessor :name
-
# validates! :name, presence: true
-
# end
-
#
-
# person = Person.new
-
# person.name = ''
-
# person.valid?
-
# # => ActiveModel::StrictValidationFailed: Name can't be blank
-
1
def validates!(*attributes)
-
options = attributes.extract_options!
-
options[:strict] = true
-
validates(*(attributes << options))
-
end
-
-
1
protected
-
-
# When creating custom validators, it might be useful to be able to specify
-
# additional default keys. This can be done by overwriting this method.
-
1
def _validates_default_keys # :nodoc:
-
2
[:if, :unless, :on, :allow_blank, :allow_nil , :strict]
-
end
-
-
1
def _parse_validates_options(options) # :nodoc:
-
2
case options
-
when TrueClass
-
2
{}
-
when Hash
-
options
-
when Range, Array
-
{ :in => options }
-
else
-
{ :with => options }
-
end
-
end
-
end
-
end
-
end
-
1
module ActiveModel
-
1
module Validations
-
1
module HelperMethods
-
1
private
-
1
def _merge_attributes(attr_names)
-
89
options = attr_names.extract_options!.symbolize_keys
-
89
attr_names.flatten!
-
89
options[:attributes] = attr_names
-
89
options
-
end
-
end
-
-
1
class WithValidator < EachValidator # :nodoc:
-
1
def validate_each(record, attr, val)
-
method_name = options[:with]
-
-
if record.method(method_name).arity == 0
-
record.send method_name
-
else
-
record.send method_name, attr
-
end
-
end
-
end
-
-
1
module ClassMethods
-
# Passes the record off to the class or classes specified and allows them
-
# to add errors based on more complex conditions.
-
#
-
# class Person
-
# include ActiveModel::Validations
-
# validates_with MyValidator
-
# end
-
#
-
# class MyValidator < ActiveModel::Validator
-
# def validate(record)
-
# if some_complex_logic
-
# record.errors.add :base, 'This record is invalid'
-
# end
-
# end
-
#
-
# private
-
# def some_complex_logic
-
# # ...
-
# end
-
# end
-
#
-
# You may also pass it multiple classes, like so:
-
#
-
# class Person
-
# include ActiveModel::Validations
-
# validates_with MyValidator, MyOtherValidator, on: :create
-
# end
-
#
-
# Configuration options:
-
# * <tt>:on</tt> - Specifies when this validation is active
-
# (<tt>:create</tt> or <tt>:update</tt>.
-
# * <tt>:if</tt> - Specifies a method, proc or string to call to determine
-
# if the validation should occur (e.g. <tt>if: :allow_validation</tt>,
-
# or <tt>if: Proc.new { |user| user.signup_step > 2 }</tt>).
-
# The method, proc or string should return or evaluate to a +true+ or
-
# +false+ value.
-
# * <tt>:unless</tt> - Specifies a method, proc or string to call to
-
# determine if the validation should not occur
-
# (e.g. <tt>unless: :skip_validation</tt>, or
-
# <tt>unless: Proc.new { |user| user.signup_step <= 2 }</tt>).
-
# The method, proc or string should return or evaluate to a +true+ or
-
# +false+ value.
-
# * <tt>:strict</tt> - Specifies whether validation should be strict.
-
# See <tt>ActiveModel::Validation#validates!</tt> for more information.
-
#
-
# If you pass any additional configuration options, they will be passed
-
# to the class and available as +options+:
-
#
-
# class Person
-
# include ActiveModel::Validations
-
# validates_with MyValidator, my_custom_key: 'my custom value'
-
# end
-
#
-
# class MyValidator < ActiveModel::Validator
-
# def validate(record)
-
# options[:my_custom_key] # => "my custom value"
-
# end
-
# end
-
1
def validates_with(*args, &block)
-
91
options = args.extract_options!
-
91
args.each do |klass|
-
91
validator = klass.new(options, &block)
-
91
validator.setup(self) if validator.respond_to?(:setup)
-
-
91
if validator.respond_to?(:attributes) && !validator.attributes.empty?
-
91
validator.attributes.each do |attribute|
-
92
_validators[attribute.to_sym] << validator
-
end
-
else
-
_validators[nil] << validator
-
end
-
-
91
validate(validator, options)
-
end
-
end
-
end
-
-
# Passes the record off to the class or classes specified and allows them
-
# to add errors based on more complex conditions.
-
#
-
# class Person
-
# include ActiveModel::Validations
-
#
-
# validate :instance_validations
-
#
-
# def instance_validations
-
# validates_with MyValidator
-
# end
-
# end
-
#
-
# Please consult the class method documentation for more information on
-
# creating your own validator.
-
#
-
# You may also pass it multiple classes, like so:
-
#
-
# class Person
-
# include ActiveModel::Validations
-
#
-
# validate :instance_validations, on: :create
-
#
-
# def instance_validations
-
# validates_with MyValidator, MyOtherValidator
-
# end
-
# end
-
#
-
# Standard configuration options (<tt>:on</tt>, <tt>:if</tt> and
-
# <tt>:unless</tt>), which are available on the class version of
-
# +validates_with+, should instead be placed on the +validates+ method
-
# as these are applied and tested in the callback.
-
#
-
# If you pass any additional configuration options, they will be passed
-
# to the class and available as +options+, please refer to the
-
# class version of this method for more information.
-
1
def validates_with(*args, &block)
-
options = args.extract_options!
-
args.each do |klass|
-
validator = klass.new(options, &block)
-
validator.validate(self)
-
end
-
end
-
end
-
end
-
1
require "active_support/core_ext/module/anonymous"
-
-
1
module ActiveModel
-
-
# == Active \Model \Validator
-
#
-
# A simple base class that can be used along with
-
# ActiveModel::Validations::ClassMethods.validates_with
-
#
-
# class Person
-
# include ActiveModel::Validations
-
# validates_with MyValidator
-
# end
-
#
-
# class MyValidator < ActiveModel::Validator
-
# def validate(record)
-
# if some_complex_logic
-
# record.errors[:base] = "This record is invalid"
-
# end
-
# end
-
#
-
# private
-
# def some_complex_logic
-
# # ...
-
# end
-
# end
-
#
-
# Any class that inherits from ActiveModel::Validator must implement a method
-
# called +validate+ which accepts a +record+.
-
#
-
# class Person
-
# include ActiveModel::Validations
-
# validates_with MyValidator
-
# end
-
#
-
# class MyValidator < ActiveModel::Validator
-
# def validate(record)
-
# record # => The person instance being validated
-
# options # => Any non-standard options passed to validates_with
-
# end
-
# end
-
#
-
# To cause a validation error, you must add to the +record+'s errors directly
-
# from within the validators message.
-
#
-
# class MyValidator < ActiveModel::Validator
-
# def validate(record)
-
# record.errors.add :base, "This is some custom error message"
-
# record.errors.add :first_name, "This is some complex validation"
-
# # etc...
-
# end
-
# end
-
#
-
# To add behavior to the initialize method, use the following signature:
-
#
-
# class MyValidator < ActiveModel::Validator
-
# def initialize(options)
-
# super
-
# @my_custom_field = options[:field_name] || :first_name
-
# end
-
# end
-
#
-
# The easiest way to add custom validators for validating individual attributes
-
# is with the convenient <tt>ActiveModel::EachValidator</tt>.
-
#
-
# class TitleValidator < ActiveModel::EachValidator
-
# def validate_each(record, attribute, value)
-
# record.errors.add attribute, 'must be Mr., Mrs., or Dr.' unless %w(Mr. Mrs. Dr.).include?(value)
-
# end
-
# end
-
#
-
# This can now be used in combination with the +validates+ method
-
# (see <tt>ActiveModel::Validations::ClassMethods.validates</tt> for more on this).
-
#
-
# class Person
-
# include ActiveModel::Validations
-
# attr_accessor :title
-
#
-
# validates :title, presence: true
-
# end
-
#
-
# Validator may also define a +setup+ instance method which will get called
-
# with the class that using that validator as its argument. This can be
-
# useful when there are prerequisites such as an +attr_accessor+ being present.
-
#
-
# class MyValidator < ActiveModel::Validator
-
# def setup(klass)
-
# klass.send :attr_accessor, :custom_attribute
-
# end
-
# end
-
#
-
# This setup method is only called when used with validation macros or the
-
# class level <tt>validates_with</tt> method.
-
1
class Validator
-
1
attr_reader :options
-
-
# Returns the kind of the validator.
-
#
-
# PresenceValidator.kind # => :presence
-
# UniquenessValidator.kind # => :uniqueness
-
1
def self.kind
-
@kind ||= name.split('::').last.underscore.sub(/_validator$/, '').to_sym unless anonymous?
-
end
-
-
# Accepts options that will be made available through the +options+ reader.
-
1
def initialize(options)
-
91
@options = options.freeze
-
end
-
-
# Return the kind for this validator.
-
#
-
# PresenceValidator.new.kind # => :presence
-
# UniquenessValidator.new.kind # => :uniqueness
-
1
def kind
-
self.class.kind
-
end
-
-
# Override this method in subclasses with validation logic, adding errors
-
# to the records +errors+ array where necessary.
-
1
def validate(record)
-
raise NotImplementedError, "Subclasses must implement a validate(record) method."
-
end
-
end
-
-
# +EachValidator+ is a validator which iterates through the attributes given
-
# in the options hash invoking the <tt>validate_each</tt> method passing in the
-
# record, attribute and value.
-
#
-
# All Active Model validations are built on top of this validator.
-
1
class EachValidator < Validator #:nodoc:
-
1
attr_reader :attributes
-
-
# Returns a new validator instance. All options will be available via the
-
# +options+ reader, however the <tt>:attributes</tt> option will be removed
-
# and instead be made available through the +attributes+ reader.
-
1
def initialize(options)
-
91
@attributes = Array(options.delete(:attributes))
-
91
raise ArgumentError, ":attributes cannot be blank" if @attributes.empty?
-
91
super
-
91
check_validity!
-
end
-
-
# Performs validation on the supplied record. By default this will call
-
# +validates_each+ to determine validity therefore subclasses should
-
# override +validates_each+ with validation logic.
-
1
def validate(record)
-
520
attributes.each do |attribute|
-
532
value = record.read_attribute_for_validation(attribute)
-
532
next if (value.nil? && options[:allow_nil]) || (value.blank? && options[:allow_blank])
-
525
validate_each(record, attribute, value)
-
end
-
end
-
-
# Override this method in subclasses with the validation logic, adding
-
# errors to the records +errors+ array where necessary.
-
1
def validate_each(record, attribute, value)
-
raise NotImplementedError, "Subclasses must implement a validate_each(record, attribute, value) method"
-
end
-
-
# Hook method that gets called by the initializer allowing verification
-
# that the arguments supplied are valid. You could for example raise an
-
# +ArgumentError+ when invalid options are supplied.
-
1
def check_validity!
-
end
-
end
-
-
# +BlockValidator+ is a special +EachValidator+ which receives a block on initialization
-
# and call this block for each attribute being validated. +validates_each+ uses this validator.
-
1
class BlockValidator < EachValidator #:nodoc:
-
1
def initialize(options, &block)
-
@block = block
-
super
-
end
-
-
1
private
-
-
1
def validate_each(record, attribute, value)
-
@block.call(record, attribute, value)
-
end
-
end
-
end
-
1
module ActiveModel
-
1
module VERSION #:nodoc:
-
1
MAJOR = 4
-
1
MINOR = 0
-
1
TINY = 0
-
1
PRE = "beta"
-
-
1
STRING = [MAJOR, MINOR, TINY, PRE].compact.join('.')
-
end
-
end
-
#--
-
# Copyright (c) 2004-2012 David Heinemeier Hansson
-
#
-
# Permission is hereby granted, free of charge, to any person obtaining
-
# a copy of this software and associated documentation files (the
-
# "Software"), to deal in the Software without restriction, including
-
# without limitation the rights to use, copy, modify, merge, publish,
-
# distribute, sublicense, and/or sell copies of the Software, and to
-
# permit persons to whom the Software is furnished to do so, subject to
-
# the following conditions:
-
#
-
# The above copyright notice and this permission notice shall be
-
# included in all copies or substantial portions of the Software.
-
#
-
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
-
# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
-
# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
-
# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
-
# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
-
# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
-
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
-
#++
-
1
require 'simplecov'
-
1
SimpleCov.start
-
1
puts "Started SimpleCov active_record.rb"
-
1
require 'active_support'
-
1
require 'active_support/rails'
-
1
require 'active_model'
-
1
require 'arel'
-
1
require 'active_record/deprecated_finders'
-
-
1
require 'active_record/version'
-
-
1
module ActiveRecord
-
1
extend ActiveSupport::Autoload
-
-
1
autoload :Base
-
1
autoload :Callbacks
-
1
autoload :Core
-
1
autoload :CounterCache
-
1
autoload :ConnectionHandling
-
1
autoload :DynamicMatchers
-
1
autoload :Explain
-
1
autoload :Inheritance
-
1
autoload :Integration
-
1
autoload :Migration
-
1
autoload :Migrator, 'active_record/migration'
-
1
autoload :ModelSchema
-
1
autoload :NestedAttributes
-
1
autoload :Observer
-
1
autoload :Persistence
-
1
autoload :QueryCache
-
1
autoload :Querying
-
1
autoload :ReadonlyAttributes
-
1
autoload :Reflection
-
1
autoload :Sanitization
-
1
autoload :Schema
-
1
autoload :SchemaDumper
-
1
autoload :SchemaMigration
-
1
autoload :Scoping
-
1
autoload :Serialization
-
1
autoload :Store
-
1
autoload :Timestamp
-
1
autoload :Transactions
-
1
autoload :Translation
-
1
autoload :Validations
-
-
1
eager_autoload do
-
1
autoload :ActiveRecordError, 'active_record/errors'
-
1
autoload :ConnectionNotEstablished, 'active_record/errors'
-
1
autoload :ConnectionAdapters, 'active_record/connection_adapters/abstract_adapter'
-
-
1
autoload :Aggregations
-
1
autoload :Associations
-
1
autoload :AttributeMethods
-
1
autoload :AttributeAssignment
-
1
autoload :AutosaveAssociation
-
-
1
autoload :Relation
-
1
autoload :NullRelation
-
-
1
autoload_under 'relation' do
-
1
autoload :QueryMethods
-
1
autoload :FinderMethods
-
1
autoload :Calculations
-
1
autoload :PredicateBuilder
-
1
autoload :SpawnMethods
-
1
autoload :Batches
-
1
autoload :Delegation
-
end
-
-
1
autoload :Result
-
end
-
-
1
module Coders
-
1
autoload :YAMLColumn, 'active_record/coders/yaml_column'
-
end
-
-
1
module AttributeMethods
-
1
extend ActiveSupport::Autoload
-
-
1
eager_autoload do
-
1
autoload :BeforeTypeCast
-
1
autoload :Dirty
-
1
autoload :PrimaryKey
-
1
autoload :Query
-
1
autoload :Read
-
1
autoload :TimeZoneConversion
-
1
autoload :Write
-
1
autoload :Serialization
-
end
-
end
-
-
1
module Locking
-
1
extend ActiveSupport::Autoload
-
-
1
eager_autoload do
-
1
autoload :Optimistic
-
1
autoload :Pessimistic
-
end
-
end
-
-
1
module ConnectionAdapters
-
1
extend ActiveSupport::Autoload
-
-
1
eager_autoload do
-
1
autoload :AbstractAdapter
-
1
autoload :ConnectionManagement, "active_record/connection_adapters/abstract/connection_pool"
-
end
-
end
-
-
1
module Scoping
-
1
extend ActiveSupport::Autoload
-
-
1
eager_autoload do
-
1
autoload :Named
-
1
autoload :Default
-
end
-
end
-
-
1
module Tasks
-
1
extend ActiveSupport::Autoload
-
-
1
autoload :DatabaseTasks
-
1
autoload :SQLiteDatabaseTasks, 'active_record/tasks/sqlite_database_tasks'
-
1
autoload :MySQLDatabaseTasks, 'active_record/tasks/mysql_database_tasks'
-
1
autoload :PostgreSQLDatabaseTasks,
-
'active_record/tasks/postgresql_database_tasks'
-
end
-
-
1
autoload :TestCase
-
1
autoload :TestFixtures, 'active_record/fixtures'
-
-
1
def self.eager_load!
-
super
-
ActiveRecord::Locking.eager_load!
-
ActiveRecord::Scoping.eager_load!
-
ActiveRecord::Associations.eager_load!
-
ActiveRecord::AttributeMethods.eager_load!
-
ActiveRecord::ConnectionAdapters.eager_load!
-
end
-
end
-
-
1
ActiveSupport.on_load(:active_record) do
-
1
Arel::Table.engine = self
-
end
-
-
1
ActiveSupport.on_load(:i18n) do
-
1
I18n.load_path << File.dirname(__FILE__) + '/active_record/locale/en.yml'
-
end
-
1
module ActiveRecord
-
# = Active Record Aggregations
-
1
module Aggregations # :nodoc:
-
1
extend ActiveSupport::Concern
-
-
1
def clear_aggregation_cache #:nodoc:
-
447
@aggregation_cache.clear if persisted?
-
end
-
-
# Active Record implements aggregation through a macro-like class method called +composed_of+
-
# for representing attributes as value objects. It expresses relationships like "Account [is]
-
# composed of Money [among other things]" or "Person [is] composed of [an] address". Each call
-
# to the macro adds a description of how the value objects are created from the attributes of
-
# the entity object (when the entity is initialized either as a new object or from finding an
-
# existing object) and how it can be turned back into attributes (when the entity is saved to
-
# the database).
-
#
-
# class Customer < ActiveRecord::Base
-
# composed_of :balance, :class_name => "Money", :mapping => %w(balance amount)
-
# composed_of :address, :mapping => [ %w(address_street street), %w(address_city city) ]
-
# end
-
#
-
# The customer class now has the following methods to manipulate the value objects:
-
# * <tt>Customer#balance, Customer#balance=(money)</tt>
-
# * <tt>Customer#address, Customer#address=(address)</tt>
-
#
-
# These methods will operate with value objects like the ones described below:
-
#
-
# class Money
-
# include Comparable
-
# attr_reader :amount, :currency
-
# EXCHANGE_RATES = { "USD_TO_DKK" => 6 }
-
#
-
# def initialize(amount, currency = "USD")
-
# @amount, @currency = amount, currency
-
# end
-
#
-
# def exchange_to(other_currency)
-
# exchanged_amount = (amount * EXCHANGE_RATES["#{currency}_TO_#{other_currency}"]).floor
-
# Money.new(exchanged_amount, other_currency)
-
# end
-
#
-
# def ==(other_money)
-
# amount == other_money.amount && currency == other_money.currency
-
# end
-
#
-
# def <=>(other_money)
-
# if currency == other_money.currency
-
# amount <=> other_money.amount
-
# else
-
# amount <=> other_money.exchange_to(currency).amount
-
# end
-
# end
-
# end
-
#
-
# class Address
-
# attr_reader :street, :city
-
# def initialize(street, city)
-
# @street, @city = street, city
-
# end
-
#
-
# def close_to?(other_address)
-
# city == other_address.city
-
# end
-
#
-
# def ==(other_address)
-
# city == other_address.city && street == other_address.street
-
# end
-
# end
-
#
-
# Now it's possible to access attributes from the database through the value objects instead. If
-
# you choose to name the composition the same as the attribute's name, it will be the only way to
-
# access that attribute. That's the case with our +balance+ attribute. You interact with the value
-
# objects just like you would with any other attribute:
-
#
-
# customer.balance = Money.new(20) # sets the Money value object and the attribute
-
# customer.balance # => Money value object
-
# customer.balance.exchange_to("DKK") # => Money.new(120, "DKK")
-
# customer.balance > Money.new(10) # => true
-
# customer.balance == Money.new(20) # => true
-
# customer.balance < Money.new(5) # => false
-
#
-
# Value objects can also be composed of multiple attributes, such as the case of Address. The order
-
# of the mappings will determine the order of the parameters.
-
#
-
# customer.address_street = "Hyancintvej"
-
# customer.address_city = "Copenhagen"
-
# customer.address # => Address.new("Hyancintvej", "Copenhagen")
-
#
-
# customer.address_street = "Vesterbrogade"
-
# customer.address # => Address.new("Hyancintvej", "Copenhagen")
-
# customer.clear_aggregation_cache
-
# customer.address # => Address.new("Vesterbrogade", "Copenhagen")
-
#
-
# customer.address = Address.new("May Street", "Chicago")
-
# customer.address_street # => "May Street"
-
# customer.address_city # => "Chicago"
-
#
-
# == Writing value objects
-
#
-
# Value objects are immutable and interchangeable objects that represent a given value, such as
-
# a Money object representing $5. Two Money objects both representing $5 should be equal (through
-
# methods such as <tt>==</tt> and <tt><=></tt> from Comparable if ranking makes sense). This is
-
# unlike entity objects where equality is determined by identity. An entity class such as Customer can
-
# easily have two different objects that both have an address on Hyancintvej. Entity identity is
-
# determined by object or relational unique identifiers (such as primary keys). Normal
-
# ActiveRecord::Base classes are entity objects.
-
#
-
# It's also important to treat the value objects as immutable. Don't allow the Money object to have
-
# its amount changed after creation. Create a new Money object with the new value instead. The
-
# Money#exchange_to method is an example of this. It returns a new value object instead of changing
-
# its own values. Active Record won't persist value objects that have been changed through means
-
# other than the writer method.
-
#
-
# The immutable requirement is enforced by Active Record by freezing any object assigned as a value
-
# object. Attempting to change it afterwards will result in a ActiveSupport::FrozenObjectError.
-
#
-
# Read more about value objects on http://c2.com/cgi/wiki?ValueObject and on the dangers of not
-
# keeping value objects immutable on http://c2.com/cgi/wiki?ValueObjectsShouldBeImmutable
-
#
-
# == Custom constructors and converters
-
#
-
# By default value objects are initialized by calling the <tt>new</tt> constructor of the value
-
# class passing each of the mapped attributes, in the order specified by the <tt>:mapping</tt>
-
# option, as arguments. If the value class doesn't support this convention then +composed_of+ allows
-
# a custom constructor to be specified.
-
#
-
# When a new value is assigned to the value object, the default assumption is that the new value
-
# is an instance of the value class. Specifying a custom converter allows the new value to be automatically
-
# converted to an instance of value class if necessary.
-
#
-
# For example, the NetworkResource model has +network_address+ and +cidr_range+ attributes that
-
# should be aggregated using the NetAddr::CIDR value class (http://netaddr.rubyforge.org). The constructor
-
# for the value class is called +create+ and it expects a CIDR address string as a parameter. New
-
# values can be assigned to the value object using either another NetAddr::CIDR object, a string
-
# or an array. The <tt>:constructor</tt> and <tt>:converter</tt> options can be used to meet
-
# these requirements:
-
#
-
# class NetworkResource < ActiveRecord::Base
-
# composed_of :cidr,
-
# :class_name => 'NetAddr::CIDR',
-
# :mapping => [ %w(network_address network), %w(cidr_range bits) ],
-
# :allow_nil => true,
-
# :constructor => Proc.new { |network_address, cidr_range| NetAddr::CIDR.create("#{network_address}/#{cidr_range}") },
-
# :converter => Proc.new { |value| NetAddr::CIDR.create(value.is_a?(Array) ? value.join('/') : value) }
-
# end
-
#
-
# # This calls the :constructor
-
# network_resource = NetworkResource.new(:network_address => '192.168.0.1', :cidr_range => 24)
-
#
-
# # These assignments will both use the :converter
-
# network_resource.cidr = [ '192.168.2.1', 8 ]
-
# network_resource.cidr = '192.168.0.1/24'
-
#
-
# # This assignment won't use the :converter as the value is already an instance of the value class
-
# network_resource.cidr = NetAddr::CIDR.create('192.168.2.1/8')
-
#
-
# # Saving and then reloading will use the :constructor on reload
-
# network_resource.save
-
# network_resource.reload
-
#
-
# == Finding records by a value object
-
#
-
# Once a +composed_of+ relationship is specified for a model, records can be loaded from the database
-
# by specifying an instance of the value object in the conditions hash. The following example
-
# finds all customers with +balance_amount+ equal to 20 and +balance_currency+ equal to "USD":
-
#
-
# Customer.where(:balance => Money.new(20, "USD")).all
-
#
-
1
module ClassMethods
-
# Adds reader and writer methods for manipulating a value object:
-
# <tt>composed_of :address</tt> adds <tt>address</tt> and <tt>address=(new_address)</tt> methods.
-
#
-
# Options are:
-
# * <tt>:class_name</tt> - Specifies the class name of the association. Use it only if that name
-
# can't be inferred from the part id. So <tt>composed_of :address</tt> will by default be linked
-
# to the Address class, but if the real class name is CompanyAddress, you'll have to specify it
-
# with this option.
-
# * <tt>:mapping</tt> - Specifies the mapping of entity attributes to attributes of the value
-
# object. Each mapping is represented as an array where the first item is the name of the
-
# entity attribute and the second item is the name of the attribute in the value object. The
-
# order in which mappings are defined determines the order in which attributes are sent to the
-
# value class constructor.
-
# * <tt>:allow_nil</tt> - Specifies that the value object will not be instantiated when all mapped
-
# attributes are +nil+. Setting the value object to +nil+ has the effect of writing +nil+ to all
-
# mapped attributes.
-
# This defaults to +false+.
-
# * <tt>:constructor</tt> - A symbol specifying the name of the constructor method or a Proc that
-
# is called to initialize the value object. The constructor is passed all of the mapped attributes,
-
# in the order that they are defined in the <tt>:mapping option</tt>, as arguments and uses them
-
# to instantiate a <tt>:class_name</tt> object.
-
# The default is <tt>:new</tt>.
-
# * <tt>:converter</tt> - A symbol specifying the name of a class method of <tt>:class_name</tt>
-
# or a Proc that is called when a new value is assigned to the value object. The converter is
-
# passed the single value that is used in the assignment and is only called if the new value is
-
# not an instance of <tt>:class_name</tt>. If <tt>:allow_nil</tt> is set to true, the converter
-
# can return nil to skip the assignment.
-
#
-
# Option examples:
-
# composed_of :temperature, :mapping => %w(reading celsius)
-
# composed_of :balance, :class_name => "Money", :mapping => %w(balance amount),
-
# :converter => Proc.new { |balance| balance.to_money }
-
# composed_of :address, :mapping => [ %w(address_street street), %w(address_city city) ]
-
# composed_of :gps_location
-
# composed_of :gps_location, :allow_nil => true
-
# composed_of :ip_address,
-
# :class_name => 'IPAddr',
-
# :mapping => %w(ip to_i),
-
# :constructor => Proc.new { |ip| IPAddr.new(ip, Socket::AF_INET) },
-
# :converter => Proc.new { |ip| ip.is_a?(Integer) ? IPAddr.new(ip, Socket::AF_INET) : IPAddr.new(ip.to_s) }
-
#
-
1
def composed_of(part_id, options = {})
-
8
options.assert_valid_keys(:class_name, :mapping, :allow_nil, :constructor, :converter)
-
-
8
name = part_id.id2name
-
8
class_name = options[:class_name] || name.camelize
-
8
mapping = options[:mapping] || [ name, name ]
-
8
mapping = [ mapping ] unless mapping.first.is_a?(Array)
-
8
allow_nil = options[:allow_nil] || false
-
8
constructor = options[:constructor] || :new
-
8
converter = options[:converter]
-
-
8
reader_method(name, class_name, mapping, allow_nil, constructor)
-
8
writer_method(name, class_name, mapping, allow_nil, converter)
-
-
8
create_reflection(:composed_of, part_id, nil, options, self)
-
end
-
-
1
private
-
1
def reader_method(name, class_name, mapping, allow_nil, constructor)
-
8
define_method(name) do
-
96
if @aggregation_cache[name].nil? && (!allow_nil || mapping.any? {|pair| !read_attribute(pair.first).nil? })
-
80
attrs = mapping.collect {|pair| read_attribute(pair.first)}
-
29
object = constructor.respond_to?(:call) ?
-
constructor.call(*attrs) :
-
class_name.constantize.send(constructor, *attrs)
-
29
@aggregation_cache[name] = object
-
end
-
69
@aggregation_cache[name]
-
end
-
end
-
-
1
def writer_method(name, class_name, mapping, allow_nil, converter)
-
8
define_method("#{name}=") do |part|
-
22
klass = class_name.constantize
-
22
unless part.is_a?(klass) || converter.nil? || part.nil?
-
2
part = converter.respond_to?(:call) ? converter.call(part) : klass.send(converter, part)
-
end
-
-
22
if part.nil? && allow_nil
-
16
mapping.each { |pair| self[pair.first] = nil }
-
6
@aggregation_cache[name] = nil
-
else
-
38
mapping.each { |pair| self[pair.first] = part.send(pair.last) }
-
14
@aggregation_cache[name] = part.freeze
-
end
-
end
-
end
-
end
-
end
-
end
-
1
require 'active_support/core_ext/enumerable'
-
1
require 'active_support/core_ext/string/conversions'
-
1
require 'active_support/core_ext/module/remove_method'
-
1
require 'active_support/dependencies/autoload'
-
1
require 'active_support/concern'
-
1
require 'active_record/errors'
-
-
1
module ActiveRecord
-
1
class InverseOfAssociationNotFoundError < ActiveRecordError #:nodoc:
-
1
def initialize(reflection, associated_class = nil)
-
5
super("Could not find the inverse association for #{reflection.name} (#{reflection.options[:inverse_of].inspect} in #{associated_class.nil? ? reflection.class_name : associated_class.name})")
-
end
-
end
-
-
1
class HasManyThroughAssociationNotFoundError < ActiveRecordError #:nodoc:
-
1
def initialize(owner_class_name, reflection)
-
1
super("Could not find the association #{reflection.options[:through].inspect} in model #{owner_class_name}")
-
end
-
end
-
-
1
class HasManyThroughAssociationPolymorphicSourceError < ActiveRecordError #:nodoc:
-
1
def initialize(owner_class_name, reflection, source_reflection)
-
1
super("Cannot have a has_many :through association '#{owner_class_name}##{reflection.name}' on the polymorphic object '#{source_reflection.class_name}##{source_reflection.name}' without 'source_type'. Try adding 'source_type: \"#{reflection.name.to_s.classify}\"' to 'has_many :through' definition.")
-
end
-
end
-
-
1
class HasManyThroughAssociationPolymorphicThroughError < ActiveRecordError #:nodoc:
-
1
def initialize(owner_class_name, reflection)
-
1
super("Cannot have a has_many :through association '#{owner_class_name}##{reflection.name}' which goes through the polymorphic association '#{owner_class_name}##{reflection.through_reflection.name}'.")
-
end
-
end
-
-
1
class HasManyThroughAssociationPointlessSourceTypeError < ActiveRecordError #:nodoc:
-
1
def initialize(owner_class_name, reflection, source_reflection)
-
super("Cannot have a has_many :through association '#{owner_class_name}##{reflection.name}' with a :source_type option if the '#{reflection.through_reflection.class_name}##{source_reflection.name}' is not polymorphic. Try removing :source_type on your association.")
-
end
-
end
-
-
1
class HasOneThroughCantAssociateThroughCollection < ActiveRecordError #:nodoc:
-
1
def initialize(owner_class_name, reflection, through_reflection)
-
1
super("Cannot have a has_one :through association '#{owner_class_name}##{reflection.name}' where the :through association '#{owner_class_name}##{through_reflection.name}' is a collection. Specify a has_one or belongs_to association in the :through option instead.")
-
end
-
end
-
-
1
class HasManyThroughSourceAssociationNotFoundError < ActiveRecordError #:nodoc:
-
1
def initialize(reflection)
-
through_reflection = reflection.through_reflection
-
source_reflection_names = reflection.source_reflection_names
-
source_associations = reflection.through_reflection.klass.reflect_on_all_associations.collect { |a| a.name.inspect }
-
super("Could not find the source association(s) #{source_reflection_names.collect{ |a| a.inspect }.to_sentence(:two_words_connector => ' or ', :last_word_connector => ', or ', :locale => :en)} in model #{through_reflection.klass}. Try 'has_many #{reflection.name.inspect}, :through => #{through_reflection.name.inspect}, :source => <name>'. Is it one of #{source_associations.to_sentence(:two_words_connector => ' or ', :last_word_connector => ', or ', :locale => :en)}?")
-
end
-
end
-
-
1
class HasManyThroughCantAssociateThroughHasOneOrManyReflection < ActiveRecordError #:nodoc:
-
1
def initialize(owner, reflection)
-
7
super("Cannot modify association '#{owner.class.name}##{reflection.name}' because the source reflection class '#{reflection.source_reflection.class_name}' is associated to '#{reflection.through_reflection.class_name}' via :#{reflection.source_reflection.macro}.")
-
end
-
end
-
-
1
class HasManyThroughCantAssociateNewRecords < ActiveRecordError #:nodoc:
-
1
def initialize(owner, reflection)
-
super("Cannot associate new records through '#{owner.class.name}##{reflection.name}' on '#{reflection.source_reflection.class_name rescue nil}##{reflection.source_reflection.name rescue nil}'. Both records must have an id in order to create the has_many :through record associating them.")
-
end
-
end
-
-
1
class HasManyThroughCantDissociateNewRecords < ActiveRecordError #:nodoc:
-
1
def initialize(owner, reflection)
-
super("Cannot dissociate new records through '#{owner.class.name}##{reflection.name}' on '#{reflection.source_reflection.class_name rescue nil}##{reflection.source_reflection.name rescue nil}'. Both records must have an id in order to delete the has_many :through record associating them.")
-
end
-
end
-
-
1
class HasManyThroughNestedAssociationsAreReadonly < ActiveRecordError #:nodoc:
-
1
def initialize(owner, reflection)
-
8
super("Cannot modify association '#{owner.class.name}##{reflection.name}' because it goes through more than one other association.")
-
end
-
end
-
-
1
class HasAndBelongsToManyAssociationForeignKeyNeeded < ActiveRecordError #:nodoc:
-
1
def initialize(reflection)
-
1
super("Cannot create self referential has_and_belongs_to_many association on '#{reflection.class_name rescue nil}##{reflection.name rescue nil}'. :association_foreign_key cannot be the same as the :foreign_key.")
-
end
-
end
-
-
1
class EagerLoadPolymorphicError < ActiveRecordError #:nodoc:
-
1
def initialize(reflection)
-
1
super("Can not eagerly load the polymorphic association #{reflection.name.inspect}")
-
end
-
end
-
-
1
class ReadOnlyAssociation < ActiveRecordError #:nodoc:
-
1
def initialize(reflection)
-
super("Can not add to a has_many :through association. Try adding to #{reflection.through_reflection.name.inspect}.")
-
end
-
end
-
-
# This error is raised when trying to destroy a parent instance in N:1 or 1:1 associations
-
# (has_many, has_one) when there is at least 1 child associated instance.
-
# ex: if @project.tasks.size > 0, DeleteRestrictionError will be raised when trying to destroy @project
-
1
class DeleteRestrictionError < ActiveRecordError #:nodoc:
-
1
def initialize(name)
-
4
super("Cannot delete record because of dependent #{name}")
-
end
-
end
-
-
# See ActiveRecord::Associations::ClassMethods for documentation.
-
1
module Associations # :nodoc:
-
1
extend ActiveSupport::Autoload
-
1
extend ActiveSupport::Concern
-
-
# These classes will be loaded when associations are created.
-
# So there is no need to eager load them.
-
1
autoload :Association, 'active_record/associations/association'
-
1
autoload :SingularAssociation, 'active_record/associations/singular_association'
-
1
autoload :CollectionAssociation, 'active_record/associations/collection_association'
-
1
autoload :CollectionProxy, 'active_record/associations/collection_proxy'
-
-
1
autoload :BelongsToAssociation, 'active_record/associations/belongs_to_association'
-
1
autoload :BelongsToPolymorphicAssociation, 'active_record/associations/belongs_to_polymorphic_association'
-
1
autoload :HasAndBelongsToManyAssociation, 'active_record/associations/has_and_belongs_to_many_association'
-
1
autoload :HasManyAssociation, 'active_record/associations/has_many_association'
-
1
autoload :HasManyThroughAssociation, 'active_record/associations/has_many_through_association'
-
1
autoload :HasOneAssociation, 'active_record/associations/has_one_association'
-
1
autoload :HasOneThroughAssociation, 'active_record/associations/has_one_through_association'
-
1
autoload :ThroughAssociation, 'active_record/associations/through_association'
-
-
1
module Builder #:nodoc:
-
1
autoload :Association, 'active_record/associations/builder/association'
-
1
autoload :SingularAssociation, 'active_record/associations/builder/singular_association'
-
1
autoload :CollectionAssociation, 'active_record/associations/builder/collection_association'
-
-
1
autoload :BelongsTo, 'active_record/associations/builder/belongs_to'
-
1
autoload :HasOne, 'active_record/associations/builder/has_one'
-
1
autoload :HasMany, 'active_record/associations/builder/has_many'
-
1
autoload :HasAndBelongsToMany, 'active_record/associations/builder/has_and_belongs_to_many'
-
end
-
-
1
eager_autoload do
-
1
autoload :Preloader, 'active_record/associations/preloader'
-
1
autoload :JoinDependency, 'active_record/associations/join_dependency'
-
1
autoload :AssociationScope, 'active_record/associations/association_scope'
-
1
autoload :AliasTracker, 'active_record/associations/alias_tracker'
-
1
autoload :JoinHelper, 'active_record/associations/join_helper'
-
end
-
-
# Clears out the association cache.
-
1
def clear_association_cache #:nodoc:
-
450
@association_cache.clear if persisted?
-
end
-
-
# :nodoc:
-
1
attr_reader :association_cache
-
-
# Returns the association instance for the given name, instantiating it if it doesn't already exist
-
1
def association(name) #:nodoc:
-
8974
association = association_instance_get(name)
-
-
8974
if association.nil?
-
4494
reflection = self.class.reflect_on_association(name)
-
4494
association = reflection.association_class.new(self, reflection)
-
4486
association_instance_set(name, association)
-
end
-
-
8966
association
-
end
-
-
1
private
-
# Returns the specified association instance if it responds to :loaded?, nil otherwise.
-
1
def association_instance_get(name)
-
49833
@association_cache[name.to_sym]
-
end
-
-
# Set the specified association instance.
-
1
def association_instance_set(name, association)
-
4486
@association_cache[name] = association
-
end
-
-
# Associations are a set of macro-like class methods for tying objects together through
-
# foreign keys. They express relationships like "Project has one Project Manager"
-
# or "Project belongs to a Portfolio". Each macro adds a number of methods to the
-
# class which are specialized according to the collection or association symbol and the
-
# options hash. It works much the same way as Ruby's own <tt>attr*</tt>
-
# methods.
-
#
-
# class Project < ActiveRecord::Base
-
# belongs_to :portfolio
-
# has_one :project_manager
-
# has_many :milestones
-
# has_and_belongs_to_many :categories
-
# end
-
#
-
# The project class now has the following methods (and more) to ease the traversal and
-
# manipulation of its relationships:
-
# * <tt>Project#portfolio, Project#portfolio=(portfolio), Project#portfolio.nil?</tt>
-
# * <tt>Project#project_manager, Project#project_manager=(project_manager), Project#project_manager.nil?,</tt>
-
# * <tt>Project#milestones.empty?, Project#milestones.size, Project#milestones, Project#milestones<<(milestone),</tt>
-
# <tt>Project#milestones.delete(milestone), Project#milestones.destroy(mileston), Project#milestones.find(milestone_id),</tt>
-
# <tt>Project#milestones.all(options), Project#milestones.build, Project#milestones.create</tt>
-
# * <tt>Project#categories.empty?, Project#categories.size, Project#categories, Project#categories<<(category1),</tt>
-
# <tt>Project#categories.delete(category1), Project#categories.destroy(category1)</tt>
-
#
-
# === A word of warning
-
#
-
# Don't create associations that have the same name as instance methods of
-
# <tt>ActiveRecord::Base</tt>. Since the association adds a method with that name to
-
# its model, it will override the inherited method and break things.
-
# For instance, +attributes+ and +connection+ would be bad choices for association names.
-
#
-
# == Auto-generated methods
-
#
-
# === Singular associations (one-to-one)
-
# | | belongs_to |
-
# generated methods | belongs_to | :polymorphic | has_one
-
# ----------------------------------+------------+--------------+---------
-
# other | X | X | X
-
# other=(other) | X | X | X
-
# build_other(attributes={}) | X | | X
-
# create_other(attributes={}) | X | | X
-
# create_other!(attributes={}) | X | | X
-
#
-
# ===Collection associations (one-to-many / many-to-many)
-
# | | | has_many
-
# generated methods | habtm | has_many | :through
-
# ----------------------------------+-------+----------+----------
-
# others | X | X | X
-
# others=(other,other,...) | X | X | X
-
# other_ids | X | X | X
-
# other_ids=(id,id,...) | X | X | X
-
# others<< | X | X | X
-
# others.push | X | X | X
-
# others.concat | X | X | X
-
# others.build(attributes={}) | X | X | X
-
# others.create(attributes={}) | X | X | X
-
# others.create!(attributes={}) | X | X | X
-
# others.size | X | X | X
-
# others.length | X | X | X
-
# others.count | X | X | X
-
# others.sum(args*,&block) | X | X | X
-
# others.empty? | X | X | X
-
# others.clear | X | X | X
-
# others.delete(other,other,...) | X | X | X
-
# others.delete_all | X | X | X
-
# others.destroy(other,other,...) | X | X | X
-
# others.destroy_all | X | X | X
-
# others.find(*args) | X | X | X
-
# others.exists? | X | X | X
-
# others.uniq | X | X | X
-
# others.reset | X | X | X
-
#
-
# === Overriding generated methods
-
#
-
# Association methods are generated in a module that is included into the model class,
-
# which allows you to easily override with your own methods and call the original
-
# generated method with +super+. For example:
-
#
-
# class Car < ActiveRecord::Base
-
# belongs_to :owner
-
# belongs_to :old_owner
-
# def owner=(new_owner)
-
# self.old_owner = self.owner
-
# super
-
# end
-
# end
-
#
-
# If your model class is <tt>Project</tt>, the module is
-
# named <tt>Project::GeneratedFeatureMethods</tt>. The GeneratedFeatureMethods module is
-
# included in the model class immediately after the (anonymous) generated attributes methods
-
# module, meaning an association will override the methods for an attribute with the same name.
-
#
-
# == Cardinality and associations
-
#
-
# Active Record associations can be used to describe one-to-one, one-to-many and many-to-many
-
# relationships between models. Each model uses an association to describe its role in
-
# the relation. The +belongs_to+ association is always used in the model that has
-
# the foreign key.
-
#
-
# === One-to-one
-
#
-
# Use +has_one+ in the base, and +belongs_to+ in the associated model.
-
#
-
# class Employee < ActiveRecord::Base
-
# has_one :office
-
# end
-
# class Office < ActiveRecord::Base
-
# belongs_to :employee # foreign key - employee_id
-
# end
-
#
-
# === One-to-many
-
#
-
# Use +has_many+ in the base, and +belongs_to+ in the associated model.
-
#
-
# class Manager < ActiveRecord::Base
-
# has_many :employees
-
# end
-
# class Employee < ActiveRecord::Base
-
# belongs_to :manager # foreign key - manager_id
-
# end
-
#
-
# === Many-to-many
-
#
-
# There are two ways to build a many-to-many relationship.
-
#
-
# The first way uses a +has_many+ association with the <tt>:through</tt> option and a join model, so
-
# there are two stages of associations.
-
#
-
# class Assignment < ActiveRecord::Base
-
# belongs_to :programmer # foreign key - programmer_id
-
# belongs_to :project # foreign key - project_id
-
# end
-
# class Programmer < ActiveRecord::Base
-
# has_many :assignments
-
# has_many :projects, :through => :assignments
-
# end
-
# class Project < ActiveRecord::Base
-
# has_many :assignments
-
# has_many :programmers, :through => :assignments
-
# end
-
#
-
# For the second way, use +has_and_belongs_to_many+ in both models. This requires a join table
-
# that has no corresponding model or primary key.
-
#
-
# class Programmer < ActiveRecord::Base
-
# has_and_belongs_to_many :projects # foreign keys in the join table
-
# end
-
# class Project < ActiveRecord::Base
-
# has_and_belongs_to_many :programmers # foreign keys in the join table
-
# end
-
#
-
# Choosing which way to build a many-to-many relationship is not always simple.
-
# If you need to work with the relationship model as its own entity,
-
# use <tt>has_many :through</tt>. Use +has_and_belongs_to_many+ when working with legacy schemas or when
-
# you never work directly with the relationship itself.
-
#
-
# == Is it a +belongs_to+ or +has_one+ association?
-
#
-
# Both express a 1-1 relationship. The difference is mostly where to place the foreign
-
# key, which goes on the table for the class declaring the +belongs_to+ relationship.
-
#
-
# class User < ActiveRecord::Base
-
# # I reference an account.
-
# belongs_to :account
-
# end
-
#
-
# class Account < ActiveRecord::Base
-
# # One user references me.
-
# has_one :user
-
# end
-
#
-
# The tables for these classes could look something like:
-
#
-
# CREATE TABLE users (
-
# id int(11) NOT NULL auto_increment,
-
# account_id int(11) default NULL,
-
# name varchar default NULL,
-
# PRIMARY KEY (id)
-
# )
-
#
-
# CREATE TABLE accounts (
-
# id int(11) NOT NULL auto_increment,
-
# name varchar default NULL,
-
# PRIMARY KEY (id)
-
# )
-
#
-
# == Unsaved objects and associations
-
#
-
# You can manipulate objects and associations before they are saved to the database, but
-
# there is some special behavior you should be aware of, mostly involving the saving of
-
# associated objects.
-
#
-
# You can set the :autosave option on a <tt>has_one</tt>, <tt>belongs_to</tt>,
-
# <tt>has_many</tt>, or <tt>has_and_belongs_to_many</tt> association. Setting it
-
# to +true+ will _always_ save the members, whereas setting it to +false+ will
-
# _never_ save the members. More details about :autosave option is available at
-
# autosave_association.rb .
-
#
-
# === One-to-one associations
-
#
-
# * Assigning an object to a +has_one+ association automatically saves that object and
-
# the object being replaced (if there is one), in order to update their foreign
-
# keys - except if the parent object is unsaved (<tt>new_record? == true</tt>).
-
# * If either of these saves fail (due to one of the objects being invalid), an
-
# <tt>ActiveRecord::RecordNotSaved</tt> exception is raised and the assignment is
-
# cancelled.
-
# * If you wish to assign an object to a +has_one+ association without saving it,
-
# use the <tt>build_association</tt> method (documented below). The object being
-
# replaced will still be saved to update its foreign key.
-
# * Assigning an object to a +belongs_to+ association does not save the object, since
-
# the foreign key field belongs on the parent. It does not save the parent either.
-
#
-
# === Collections
-
#
-
# * Adding an object to a collection (+has_many+ or +has_and_belongs_to_many+) automatically
-
# saves that object, except if the parent object (the owner of the collection) is not yet
-
# stored in the database.
-
# * If saving any of the objects being added to a collection (via <tt>push</tt> or similar)
-
# fails, then <tt>push</tt> returns +false+.
-
# * If saving fails while replacing the collection (via <tt>association=</tt>), an
-
# <tt>ActiveRecord::RecordNotSaved</tt> exception is raised and the assignment is
-
# cancelled.
-
# * You can add an object to a collection without automatically saving it by using the
-
# <tt>collection.build</tt> method (documented below).
-
# * All unsaved (<tt>new_record? == true</tt>) members of the collection are automatically
-
# saved when the parent is saved.
-
#
-
# == Customizing the query
-
#
-
# Associations are built from <tt>Relation</tt>s, and you can use the <tt>Relation</tt> syntax
-
# to customize them. For example, to add a condition:
-
#
-
# class Blog < ActiveRecord::Base
-
# has_many :published_posts, -> { where published: true }, class_name: 'Post'
-
# end
-
#
-
# Inside the <tt>-> { ... }</tt> block you can use all of the usual <tt>Relation</tt> methods.
-
#
-
# === Accessing the owner object
-
#
-
# Sometimes it is useful to have access to the owner object when building the query. The owner
-
# is passed as a parameter to the block. For example, the following association would find all
-
# events that occur on the user's birthday:
-
#
-
# class User < ActiveRecord::Base
-
# has_many :birthday_events, ->(user) { where starts_on: user.birthday }, class_name: 'Event'
-
# end
-
#
-
# == Association callbacks
-
#
-
# Similar to the normal callbacks that hook into the life cycle of an Active Record object,
-
# you can also define callbacks that get triggered when you add an object to or remove an
-
# object from an association collection.
-
#
-
# class Project
-
# has_and_belongs_to_many :developers, :after_add => :evaluate_velocity
-
#
-
# def evaluate_velocity(developer)
-
# ...
-
# end
-
# end
-
#
-
# It's possible to stack callbacks by passing them as an array. Example:
-
#
-
# class Project
-
# has_and_belongs_to_many :developers,
-
# :after_add => [:evaluate_velocity, Proc.new { |p, d| p.shipping_date = Time.now}]
-
# end
-
#
-
# Possible callbacks are: +before_add+, +after_add+, +before_remove+ and +after_remove+.
-
#
-
# Should any of the +before_add+ callbacks throw an exception, the object does not get
-
# added to the collection. Same with the +before_remove+ callbacks; if an exception is
-
# thrown the object doesn't get removed.
-
#
-
# == Association extensions
-
#
-
# The proxy objects that control the access to associations can be extended through anonymous
-
# modules. This is especially beneficial for adding new finders, creators, and other
-
# factory-type methods that are only used as part of this association.
-
#
-
# class Account < ActiveRecord::Base
-
# has_many :people do
-
# def find_or_create_by_name(name)
-
# first_name, last_name = name.split(" ", 2)
-
# find_or_create_by_first_name_and_last_name(first_name, last_name)
-
# end
-
# end
-
# end
-
#
-
# person = Account.first.people.find_or_create_by_name("David Heinemeier Hansson")
-
# person.first_name # => "David"
-
# person.last_name # => "Heinemeier Hansson"
-
#
-
# If you need to share the same extensions between many associations, you can use a named
-
# extension module.
-
#
-
# module FindOrCreateByNameExtension
-
# def find_or_create_by_name(name)
-
# first_name, last_name = name.split(" ", 2)
-
# find_or_create_by_first_name_and_last_name(first_name, last_name)
-
# end
-
# end
-
#
-
# class Account < ActiveRecord::Base
-
# has_many :people, -> { extending FindOrCreateByNameExtension }
-
# end
-
#
-
# class Company < ActiveRecord::Base
-
# has_many :people, -> { extending FindOrCreateByNameExtension }
-
# end
-
#
-
# Some extensions can only be made to work with knowledge of the association's internals.
-
# Extensions can access relevant state using the following methods (where +items+ is the
-
# name of the association):
-
#
-
# * <tt>record.association(:items).owner</tt> - Returns the object the association is part of.
-
# * <tt>record.association(:items).reflection</tt> - Returns the reflection object that describes the association.
-
# * <tt>record.association(:items).target</tt> - Returns the associated object for +belongs_to+ and +has_one+, or
-
# the collection of associated objects for +has_many+ and +has_and_belongs_to_many+.
-
#
-
# However, inside the actual extension code, you will not have access to the <tt>record</tt> as
-
# above. In this case, you can access <tt>proxy_association</tt>. For example,
-
# <tt>record.association(:items)</tt> and <tt>record.items.proxy_association</tt> will return
-
# the same object, allowing you to make calls like <tt>proxy_association.owner</tt> inside
-
# association extensions.
-
#
-
# == Association Join Models
-
#
-
# Has Many associations can be configured with the <tt>:through</tt> option to use an
-
# explicit join model to retrieve the data. This operates similarly to a
-
# +has_and_belongs_to_many+ association. The advantage is that you're able to add validations,
-
# callbacks, and extra attributes on the join model. Consider the following schema:
-
#
-
# class Author < ActiveRecord::Base
-
# has_many :authorships
-
# has_many :books, :through => :authorships
-
# end
-
#
-
# class Authorship < ActiveRecord::Base
-
# belongs_to :author
-
# belongs_to :book
-
# end
-
#
-
# @author = Author.first
-
# @author.authorships.collect { |a| a.book } # selects all books that the author's authorships belong to
-
# @author.books # selects all books by using the Authorship join model
-
#
-
# You can also go through a +has_many+ association on the join model:
-
#
-
# class Firm < ActiveRecord::Base
-
# has_many :clients
-
# has_many :invoices, :through => :clients
-
# end
-
#
-
# class Client < ActiveRecord::Base
-
# belongs_to :firm
-
# has_many :invoices
-
# end
-
#
-
# class Invoice < ActiveRecord::Base
-
# belongs_to :client
-
# end
-
#
-
# @firm = Firm.first
-
# @firm.clients.collect { |c| c.invoices }.flatten # select all invoices for all clients of the firm
-
# @firm.invoices # selects all invoices by going through the Client join model
-
#
-
# Similarly you can go through a +has_one+ association on the join model:
-
#
-
# class Group < ActiveRecord::Base
-
# has_many :users
-
# has_many :avatars, :through => :users
-
# end
-
#
-
# class User < ActiveRecord::Base
-
# belongs_to :group
-
# has_one :avatar
-
# end
-
#
-
# class Avatar < ActiveRecord::Base
-
# belongs_to :user
-
# end
-
#
-
# @group = Group.first
-
# @group.users.collect { |u| u.avatar }.compact # select all avatars for all users in the group
-
# @group.avatars # selects all avatars by going through the User join model.
-
#
-
# An important caveat with going through +has_one+ or +has_many+ associations on the
-
# join model is that these associations are *read-only*. For example, the following
-
# would not work following the previous example:
-
#
-
# @group.avatars << Avatar.new # this would work if User belonged_to Avatar rather than the other way around
-
# @group.avatars.delete(@group.avatars.last) # so would this
-
#
-
# If you are using a +belongs_to+ on the join model, it is a good idea to set the
-
# <tt>:inverse_of</tt> option on the +belongs_to+, which will mean that the following example
-
# works correctly (where <tt>tags</tt> is a +has_many+ <tt>:through</tt> association):
-
#
-
# @post = Post.first
-
# @tag = @post.tags.build :name => "ruby"
-
# @tag.save
-
#
-
# The last line ought to save the through record (a <tt>Taggable</tt>). This will only work if the
-
# <tt>:inverse_of</tt> is set:
-
#
-
# class Taggable < ActiveRecord::Base
-
# belongs_to :post
-
# belongs_to :tag, :inverse_of => :taggings
-
# end
-
#
-
# == Nested Associations
-
#
-
# You can actually specify *any* association with the <tt>:through</tt> option, including an
-
# association which has a <tt>:through</tt> option itself. For example:
-
#
-
# class Author < ActiveRecord::Base
-
# has_many :posts
-
# has_many :comments, :through => :posts
-
# has_many :commenters, :through => :comments
-
# end
-
#
-
# class Post < ActiveRecord::Base
-
# has_many :comments
-
# end
-
#
-
# class Comment < ActiveRecord::Base
-
# belongs_to :commenter
-
# end
-
#
-
# @author = Author.first
-
# @author.commenters # => People who commented on posts written by the author
-
#
-
# An equivalent way of setting up this association this would be:
-
#
-
# class Author < ActiveRecord::Base
-
# has_many :posts
-
# has_many :commenters, :through => :posts
-
# end
-
#
-
# class Post < ActiveRecord::Base
-
# has_many :comments
-
# has_many :commenters, :through => :comments
-
# end
-
#
-
# class Comment < ActiveRecord::Base
-
# belongs_to :commenter
-
# end
-
#
-
# When using nested association, you will not be able to modify the association because there
-
# is not enough information to know what modification to make. For example, if you tried to
-
# add a <tt>Commenter</tt> in the example above, there would be no way to tell how to set up the
-
# intermediate <tt>Post</tt> and <tt>Comment</tt> objects.
-
#
-
# == Polymorphic Associations
-
#
-
# Polymorphic associations on models are not restricted on what types of models they
-
# can be associated with. Rather, they specify an interface that a +has_many+ association
-
# must adhere to.
-
#
-
# class Asset < ActiveRecord::Base
-
# belongs_to :attachable, :polymorphic => true
-
# end
-
#
-
# class Post < ActiveRecord::Base
-
# has_many :assets, :as => :attachable # The :as option specifies the polymorphic interface to use.
-
# end
-
#
-
# @asset.attachable = @post
-
#
-
# This works by using a type column in addition to a foreign key to specify the associated
-
# record. In the Asset example, you'd need an +attachable_id+ integer column and an
-
# +attachable_type+ string column.
-
#
-
# Using polymorphic associations in combination with single table inheritance (STI) is
-
# a little tricky. In order for the associations to work as expected, ensure that you
-
# store the base model for the STI models in the type column of the polymorphic
-
# association. To continue with the asset example above, suppose there are guest posts
-
# and member posts that use the posts table for STI. In this case, there must be a +type+
-
# column in the posts table.
-
#
-
# class Asset < ActiveRecord::Base
-
# belongs_to :attachable, :polymorphic => true
-
#
-
# def attachable_type=(sType)
-
# super(sType.to_s.classify.constantize.base_class.to_s)
-
# end
-
# end
-
#
-
# class Post < ActiveRecord::Base
-
# # because we store "Post" in attachable_type now :dependent => :destroy will work
-
# has_many :assets, :as => :attachable, :dependent => :destroy
-
# end
-
#
-
# class GuestPost < Post
-
# end
-
#
-
# class MemberPost < Post
-
# end
-
#
-
# == Caching
-
#
-
# All of the methods are built on a simple caching principle that will keep the result
-
# of the last query around unless specifically instructed not to. The cache is even
-
# shared across methods to make it even cheaper to use the macro-added methods without
-
# worrying too much about performance at the first go.
-
#
-
# project.milestones # fetches milestones from the database
-
# project.milestones.size # uses the milestone cache
-
# project.milestones.empty? # uses the milestone cache
-
# project.milestones(true).size # fetches milestones from the database
-
# project.milestones # uses the milestone cache
-
#
-
# == Eager loading of associations
-
#
-
# Eager loading is a way to find objects of a certain class and a number of named associations.
-
# This is one of the easiest ways of to prevent the dreaded 1+N problem in which fetching 100
-
# posts that each need to display their author triggers 101 database queries. Through the
-
# use of eager loading, the 101 queries can be reduced to 2.
-
#
-
# class Post < ActiveRecord::Base
-
# belongs_to :author
-
# has_many :comments
-
# end
-
#
-
# Consider the following loop using the class above:
-
#
-
# Post.all.each do |post|
-
# puts "Post: " + post.title
-
# puts "Written by: " + post.author.name
-
# puts "Last comment on: " + post.comments.first.created_on
-
# end
-
#
-
# To iterate over these one hundred posts, we'll generate 201 database queries. Let's
-
# first just optimize it for retrieving the author:
-
#
-
# Post.includes(:author).each do |post|
-
#
-
# This references the name of the +belongs_to+ association that also used the <tt>:author</tt>
-
# symbol. After loading the posts, find will collect the +author_id+ from each one and load
-
# all the referenced authors with one query. Doing so will cut down the number of queries
-
# from 201 to 102.
-
#
-
# We can improve upon the situation further by referencing both associations in the finder with:
-
#
-
# Post.includes(:author, :comments).each do |post|
-
#
-
# This will load all comments with a single query. This reduces the total number of queries
-
# to 3. More generally the number of queries will be 1 plus the number of associations
-
# named (except if some of the associations are polymorphic +belongs_to+ - see below).
-
#
-
# To include a deep hierarchy of associations, use a hash:
-
#
-
# Post.includes(:author, {:comments => {:author => :gravatar}}).each do |post|
-
#
-
# That'll grab not only all the comments but all their authors and gravatar pictures.
-
# You can mix and match symbols, arrays and hashes in any combination to describe the
-
# associations you want to load.
-
#
-
# All of this power shouldn't fool you into thinking that you can pull out huge amounts
-
# of data with no performance penalty just because you've reduced the number of queries.
-
# The database still needs to send all the data to Active Record and it still needs to
-
# be processed. So it's no catch-all for performance problems, but it's a great way to
-
# cut down on the number of queries in a situation as the one described above.
-
#
-
# Since only one table is loaded at a time, conditions or orders cannot reference tables
-
# other than the main one. If this is the case Active Record falls back to the previously
-
# used LEFT OUTER JOIN based strategy. For example
-
#
-
# Post.includes([:author, :comments]).where(['comments.approved = ?', true]).all
-
#
-
# This will result in a single SQL query with joins along the lines of:
-
# <tt>LEFT OUTER JOIN comments ON comments.post_id = posts.id</tt> and
-
# <tt>LEFT OUTER JOIN authors ON authors.id = posts.author_id</tt>. Note that using conditions
-
# like this can have unintended consequences.
-
# In the above example posts with no approved comments are not returned at all, because
-
# the conditions apply to the SQL statement as a whole and not just to the association.
-
# You must disambiguate column references for this fallback to happen, for example
-
# <tt>:order => "author.name DESC"</tt> will work but <tt>:order => "name DESC"</tt> will not.
-
#
-
# If you do want eager load only some members of an association it is usually more natural
-
# to include an association which has conditions defined on it:
-
#
-
# class Post < ActiveRecord::Base
-
# has_many :approved_comments, -> { where approved: true }, :class_name => 'Comment'
-
# end
-
#
-
# Post.includes(:approved_comments)
-
#
-
# This will load posts and eager load the +approved_comments+ association, which contains
-
# only those comments that have been approved.
-
#
-
# If you eager load an association with a specified <tt>:limit</tt> option, it will be ignored,
-
# returning all the associated objects:
-
#
-
# class Picture < ActiveRecord::Base
-
# has_many :most_recent_comments, -> { order('id DESC').limit(10) }, :class_name => 'Comment'
-
# end
-
#
-
# Picture.includes(:most_recent_comments).first.most_recent_comments # => returns all associated comments.
-
#
-
# Eager loading is supported with polymorphic associations.
-
#
-
# class Address < ActiveRecord::Base
-
# belongs_to :addressable, :polymorphic => true
-
# end
-
#
-
# A call that tries to eager load the addressable model
-
#
-
# Address.includes(:addressable)
-
#
-
# This will execute one query to load the addresses and load the addressables with one
-
# query per addressable type.
-
# For example if all the addressables are either of class Person or Company then a total
-
# of 3 queries will be executed. The list of addressable types to load is determined on
-
# the back of the addresses loaded. This is not supported if Active Record has to fallback
-
# to the previous implementation of eager loading and will raise ActiveRecord::EagerLoadPolymorphicError.
-
# The reason is that the parent model's type is a column value so its corresponding table
-
# name cannot be put in the +FROM+/+JOIN+ clauses of that query.
-
#
-
# == Table Aliasing
-
#
-
# Active Record uses table aliasing in the case that a table is referenced multiple times
-
# in a join. If a table is referenced only once, the standard table name is used. The
-
# second time, the table is aliased as <tt>#{reflection_name}_#{parent_table_name}</tt>.
-
# Indexes are appended for any more successive uses of the table name.
-
#
-
# Post.joins(:comments)
-
# # => SELECT ... FROM posts INNER JOIN comments ON ...
-
# Post.joins(:special_comments) # STI
-
# # => SELECT ... FROM posts INNER JOIN comments ON ... AND comments.type = 'SpecialComment'
-
# Post.joins(:comments, :special_comments) # special_comments is the reflection name, posts is the parent table name
-
# # => SELECT ... FROM posts INNER JOIN comments ON ... INNER JOIN comments special_comments_posts
-
#
-
# Acts as tree example:
-
#
-
# TreeMixin.joins(:children)
-
# # => SELECT ... FROM mixins INNER JOIN mixins childrens_mixins ...
-
# TreeMixin.joins(:children => :parent)
-
# # => SELECT ... FROM mixins INNER JOIN mixins childrens_mixins ...
-
# INNER JOIN parents_mixins ...
-
# TreeMixin.joins(:children => {:parent => :children})
-
# # => SELECT ... FROM mixins INNER JOIN mixins childrens_mixins ...
-
# INNER JOIN parents_mixins ...
-
# INNER JOIN mixins childrens_mixins_2
-
#
-
# Has and Belongs to Many join tables use the same idea, but add a <tt>_join</tt> suffix:
-
#
-
# Post.joins(:categories)
-
# # => SELECT ... FROM posts INNER JOIN categories_posts ... INNER JOIN categories ...
-
# Post.joins(:categories => :posts)
-
# # => SELECT ... FROM posts INNER JOIN categories_posts ... INNER JOIN categories ...
-
# INNER JOIN categories_posts posts_categories_join INNER JOIN posts posts_categories
-
# Post.joins(:categories => {:posts => :categories})
-
# # => SELECT ... FROM posts INNER JOIN categories_posts ... INNER JOIN categories ...
-
# INNER JOIN categories_posts posts_categories_join INNER JOIN posts posts_categories
-
# INNER JOIN categories_posts categories_posts_join INNER JOIN categories categories_posts_2
-
#
-
# If you wish to specify your own custom joins using <tt>joins</tt> method, those table
-
# names will take precedence over the eager associations:
-
#
-
# Post.joins(:comments).joins("inner join comments ...")
-
# # => SELECT ... FROM posts INNER JOIN comments_posts ON ... INNER JOIN comments ...
-
# Post.joins(:comments, :special_comments).joins("inner join comments ...")
-
# # => SELECT ... FROM posts INNER JOIN comments comments_posts ON ...
-
# INNER JOIN comments special_comments_posts ...
-
# INNER JOIN comments ...
-
#
-
# Table aliases are automatically truncated according to the maximum length of table identifiers
-
# according to the specific database.
-
#
-
# == Modules
-
#
-
# By default, associations will look for objects within the current module scope. Consider:
-
#
-
# module MyApplication
-
# module Business
-
# class Firm < ActiveRecord::Base
-
# has_many :clients
-
# end
-
#
-
# class Client < ActiveRecord::Base; end
-
# end
-
# end
-
#
-
# When <tt>Firm#clients</tt> is called, it will in turn call
-
# <tt>MyApplication::Business::Client.find_all_by_firm_id(firm.id)</tt>.
-
# If you want to associate with a class in another module scope, this can be done by
-
# specifying the complete class name.
-
#
-
# module MyApplication
-
# module Business
-
# class Firm < ActiveRecord::Base; end
-
# end
-
#
-
# module Billing
-
# class Account < ActiveRecord::Base
-
# belongs_to :firm, :class_name => "MyApplication::Business::Firm"
-
# end
-
# end
-
# end
-
#
-
# == Bi-directional associations
-
#
-
# When you specify an association there is usually an association on the associated model
-
# that specifies the same relationship in reverse. For example, with the following models:
-
#
-
# class Dungeon < ActiveRecord::Base
-
# has_many :traps
-
# has_one :evil_wizard
-
# end
-
#
-
# class Trap < ActiveRecord::Base
-
# belongs_to :dungeon
-
# end
-
#
-
# class EvilWizard < ActiveRecord::Base
-
# belongs_to :dungeon
-
# end
-
#
-
# The +traps+ association on +Dungeon+ and the +dungeon+ association on +Trap+ are
-
# the inverse of each other and the inverse of the +dungeon+ association on +EvilWizard+
-
# is the +evil_wizard+ association on +Dungeon+ (and vice-versa). By default,
-
# Active Record doesn't know anything about these inverse relationships and so no object
-
# loading optimization is possible. For example:
-
#
-
# d = Dungeon.first
-
# t = d.traps.first
-
# d.level == t.dungeon.level # => true
-
# d.level = 10
-
# d.level == t.dungeon.level # => false
-
#
-
# The +Dungeon+ instances +d+ and <tt>t.dungeon</tt> in the above example refer to
-
# the same object data from the database, but are actually different in-memory copies
-
# of that data. Specifying the <tt>:inverse_of</tt> option on associations lets you tell
-
# Active Record about inverse relationships and it will optimise object loading. For
-
# example, if we changed our model definitions to:
-
#
-
# class Dungeon < ActiveRecord::Base
-
# has_many :traps, :inverse_of => :dungeon
-
# has_one :evil_wizard, :inverse_of => :dungeon
-
# end
-
#
-
# class Trap < ActiveRecord::Base
-
# belongs_to :dungeon, :inverse_of => :traps
-
# end
-
#
-
# class EvilWizard < ActiveRecord::Base
-
# belongs_to :dungeon, :inverse_of => :evil_wizard
-
# end
-
#
-
# Then, from our code snippet above, +d+ and <tt>t.dungeon</tt> are actually the same
-
# in-memory instance and our final <tt>d.level == t.dungeon.level</tt> will return +true+.
-
#
-
# There are limitations to <tt>:inverse_of</tt> support:
-
#
-
# * does not work with <tt>:through</tt> associations.
-
# * does not work with <tt>:polymorphic</tt> associations.
-
# * for +belongs_to+ associations +has_many+ inverse associations are ignored.
-
#
-
# == Deleting from associations
-
#
-
# === Dependent associations
-
#
-
# +has_many+, +has_one+ and +belongs_to+ associations support the <tt>:dependent</tt> option.
-
# This allows you to specify that associated records should be deleted when the owner is
-
# deleted.
-
#
-
# For example:
-
#
-
# class Author
-
# has_many :posts, :dependent => :destroy
-
# end
-
# Author.find(1).destroy # => Will destroy all of the author's posts, too
-
#
-
# The <tt>:dependent</tt> option can have different values which specify how the deletion
-
# is done. For more information, see the documentation for this option on the different
-
# specific association types. When no option is given, the behaviour is to do nothing
-
# with the associated records when destroying a record.
-
#
-
# Note that <tt>:dependent</tt> is implemented using Rails' callback
-
# system, which works by processing callbacks in order. Therefore, other
-
# callbacks declared either before or after the <tt>:dependent</tt> option
-
# can affect what it does.
-
#
-
# === Delete or destroy?
-
#
-
# +has_many+ and +has_and_belongs_to_many+ associations have the methods <tt>destroy</tt>,
-
# <tt>delete</tt>, <tt>destroy_all</tt> and <tt>delete_all</tt>.
-
#
-
# For +has_and_belongs_to_many+, <tt>delete</tt> and <tt>destroy</tt> are the same: they
-
# cause the records in the join table to be removed.
-
#
-
# For +has_many+, <tt>destroy</tt> will always call the <tt>destroy</tt> method of the
-
# record(s) being removed so that callbacks are run. However <tt>delete</tt> will either
-
# do the deletion according to the strategy specified by the <tt>:dependent</tt> option, or
-
# if no <tt>:dependent</tt> option is given, then it will follow the default strategy.
-
# The default strategy is <tt>:nullify</tt> (set the foreign keys to <tt>nil</tt>), except for
-
# +has_many+ <tt>:through</tt>, where the default strategy is <tt>delete_all</tt> (delete
-
# the join records, without running their callbacks).
-
#
-
# There is also a <tt>clear</tt> method which is the same as <tt>delete_all</tt>, except that
-
# it returns the association rather than the records which have been deleted.
-
#
-
# === What gets deleted?
-
#
-
# There is a potential pitfall here: +has_and_belongs_to_many+ and +has_many+ <tt>:through</tt>
-
# associations have records in join tables, as well as the associated records. So when we
-
# call one of these deletion methods, what exactly should be deleted?
-
#
-
# The answer is that it is assumed that deletion on an association is about removing the
-
# <i>link</i> between the owner and the associated object(s), rather than necessarily the
-
# associated objects themselves. So with +has_and_belongs_to_many+ and +has_many+
-
# <tt>:through</tt>, the join records will be deleted, but the associated records won't.
-
#
-
# This makes sense if you think about it: if you were to call <tt>post.tags.delete(Tag.find_by_name('food'))</tt>
-
# you would want the 'food' tag to be unlinked from the post, rather than for the tag itself
-
# to be removed from the database.
-
#
-
# However, there are examples where this strategy doesn't make sense. For example, suppose
-
# a person has many projects, and each project has many tasks. If we deleted one of a person's
-
# tasks, we would probably not want the project to be deleted. In this scenario, the delete method
-
# won't actually work: it can only be used if the association on the join model is a
-
# +belongs_to+. In other situations you are expected to perform operations directly on
-
# either the associated records or the <tt>:through</tt> association.
-
#
-
# With a regular +has_many+ there is no distinction between the "associated records"
-
# and the "link", so there is only one choice for what gets deleted.
-
#
-
# With +has_and_belongs_to_many+ and +has_many+ <tt>:through</tt>, if you want to delete the
-
# associated records themselves, you can always do something along the lines of
-
# <tt>person.tasks.each(&:destroy)</tt>.
-
#
-
# == Type safety with <tt>ActiveRecord::AssociationTypeMismatch</tt>
-
#
-
# If you attempt to assign an object to an association that doesn't match the inferred
-
# or specified <tt>:class_name</tt>, you'll get an <tt>ActiveRecord::AssociationTypeMismatch</tt>.
-
#
-
# == Options
-
#
-
# All of the association macros can be specialized through options. This makes cases
-
# more complex than the simple and guessable ones possible.
-
1
module ClassMethods
-
# Specifies a one-to-many association. The following methods for retrieval and query of
-
# collections of associated objects will be added:
-
#
-
# [collection(force_reload = false)]
-
# Returns an array of all the associated objects.
-
# An empty array is returned if none are found.
-
# [collection<<(object, ...)]
-
# Adds one or more objects to the collection by setting their foreign keys to the collection's primary key.
-
# Note that this operation instantly fires update sql without waiting for the save or update call on the
-
# parent object.
-
# [collection.delete(object, ...)]
-
# Removes one or more objects from the collection by setting their foreign keys to +NULL+.
-
# Objects will be in addition destroyed if they're associated with <tt>:dependent => :destroy</tt>,
-
# and deleted if they're associated with <tt>:dependent => :delete_all</tt>.
-
#
-
# If the <tt>:through</tt> option is used, then the join records are deleted (rather than
-
# nullified) by default, but you can specify <tt>:dependent => :destroy</tt> or
-
# <tt>:dependent => :nullify</tt> to override this.
-
# [collection.destroy(object, ...)]
-
# Removes one or more objects from the collection by running <tt>destroy</tt> on
-
# each record, regardless of any dependent option, ensuring callbacks are run.
-
#
-
# If the <tt>:through</tt> option is used, then the join records are destroyed
-
# instead, not the objects themselves.
-
# [collection=objects]
-
# Replaces the collections content by deleting and adding objects as appropriate. If the <tt>:through</tt>
-
# option is true callbacks in the join models are triggered except destroy callbacks, since deletion is
-
# direct.
-
# [collection_singular_ids]
-
# Returns an array of the associated objects' ids
-
# [collection_singular_ids=ids]
-
# Replace the collection with the objects identified by the primary keys in +ids+. This
-
# method loads the models and calls <tt>collection=</tt>. See above.
-
# [collection.clear]
-
# Removes every object from the collection. This destroys the associated objects if they
-
# are associated with <tt>:dependent => :destroy</tt>, deletes them directly from the
-
# database if <tt>:dependent => :delete_all</tt>, otherwise sets their foreign keys to +NULL+.
-
# If the <tt>:through</tt> option is true no destroy callbacks are invoked on the join models.
-
# Join models are directly deleted.
-
# [collection.empty?]
-
# Returns +true+ if there are no associated objects.
-
# [collection.size]
-
# Returns the number of associated objects.
-
# [collection.find(...)]
-
# Finds an associated object according to the same rules as ActiveRecord::Base.find.
-
# [collection.exists?(...)]
-
# Checks whether an associated object with the given conditions exists.
-
# Uses the same rules as ActiveRecord::Base.exists?.
-
# [collection.build(attributes = {}, ...)]
-
# Returns one or more new objects of the collection type that have been instantiated
-
# with +attributes+ and linked to this object through a foreign key, but have not yet
-
# been saved.
-
# [collection.create(attributes = {})]
-
# Returns a new object of the collection type that has been instantiated
-
# with +attributes+, linked to this object through a foreign key, and that has already
-
# been saved (if it passed the validation). *Note*: This only works if the base model
-
# already exists in the DB, not if it is a new (unsaved) record!
-
#
-
# (*Note*: +collection+ is replaced with the symbol passed as the first argument, so
-
# <tt>has_many :clients</tt> would add among others <tt>clients.empty?</tt>.)
-
#
-
# === Example
-
#
-
# Example: A Firm class declares <tt>has_many :clients</tt>, which will add:
-
# * <tt>Firm#clients</tt> (similar to <tt>Clients.all :conditions => ["firm_id = ?", id]</tt>)
-
# * <tt>Firm#clients<<</tt>
-
# * <tt>Firm#clients.delete</tt>
-
# * <tt>Firm#clients.destroy</tt>
-
# * <tt>Firm#clients=</tt>
-
# * <tt>Firm#client_ids</tt>
-
# * <tt>Firm#client_ids=</tt>
-
# * <tt>Firm#clients.clear</tt>
-
# * <tt>Firm#clients.empty?</tt> (similar to <tt>firm.clients.size == 0</tt>)
-
# * <tt>Firm#clients.size</tt> (similar to <tt>Client.count "firm_id = #{id}"</tt>)
-
# * <tt>Firm#clients.find</tt> (similar to <tt>Client.find(id, :conditions => "firm_id = #{id}")</tt>)
-
# * <tt>Firm#clients.exists?(:name => 'ACME')</tt> (similar to <tt>Client.exists?(:name => 'ACME', :firm_id => firm.id)</tt>)
-
# * <tt>Firm#clients.build</tt> (similar to <tt>Client.new("firm_id" => id)</tt>)
-
# * <tt>Firm#clients.create</tt> (similar to <tt>c = Client.new("firm_id" => id); c.save; c</tt>)
-
# The declaration can also include an options hash to specialize the behavior of the association.
-
#
-
# === Options
-
# [:class_name]
-
# Specify the class name of the association. Use it only if that name can't be inferred
-
# from the association name. So <tt>has_many :products</tt> will by default be linked
-
# to the Product class, but if the real class name is SpecialProduct, you'll have to
-
# specify it with this option.
-
# [:foreign_key]
-
# Specify the foreign key used for the association. By default this is guessed to be the name
-
# of this class in lower-case and "_id" suffixed. So a Person class that makes a +has_many+
-
# association will use "person_id" as the default <tt>:foreign_key</tt>.
-
# [:primary_key]
-
# Specify the method that returns the primary key used for the association. By default this is +id+.
-
# [:dependent]
-
# Controls what happens to the associated objects when
-
# their owner is destroyed. Note that these are implemented as
-
# callbacks, and Rails executes callbacks in order. Therefore, other
-
# similar callbacks may affect the :dependent behavior, and the
-
# :dependent behavior may affect other callbacks.
-
#
-
# * <tt>:destroy</tt> causes all the associated objects to also be destroyed
-
# * <tt>:delete_all</tt> causes all the asssociated objects to be deleted directly from the database (so callbacks will not execute)
-
# * <tt>:nullify</tt> causes the foreign keys to be set to +NULL+. Callbacks are not executed.
-
# * <tt>:restrict_with_exception</tt> causes an exception to be raised if there are any associated records
-
# * <tt>:restrict_with_error</tt> causes an error to be added to the owner if there are any associated objects
-
#
-
# If using with the <tt>:through</tt> option, the association on the join model must be
-
# a +belongs_to+, and the records which get deleted are the join records, rather than
-
# the associated records.
-
# [:counter_cache]
-
# This option can be used to configure a custom named <tt>:counter_cache.</tt> You only need this option,
-
# when you customized the name of your <tt>:counter_cache</tt> on the <tt>belongs_to</tt> association.
-
# [:as]
-
# Specifies a polymorphic interface (See <tt>belongs_to</tt>).
-
# [:through]
-
# Specifies an association through which to perform the query. This can be any other type
-
# of association, including other <tt>:through</tt> associations. Options for <tt>:class_name</tt>,
-
# <tt>:primary_key</tt> and <tt>:foreign_key</tt> are ignored, as the association uses the
-
# source reflection.
-
#
-
# If the association on the join model is a +belongs_to+, the collection can be modified
-
# and the records on the <tt>:through</tt> model will be automatically created and removed
-
# as appropriate. Otherwise, the collection is read-only, so you should manipulate the
-
# <tt>:through</tt> association directly.
-
#
-
# If you are going to modify the association (rather than just read from it), then it is
-
# a good idea to set the <tt>:inverse_of</tt> option on the source association on the
-
# join model. This allows associated records to be built which will automatically create
-
# the appropriate join model records when they are saved. (See the 'Association Join Models'
-
# section above.)
-
# [:source]
-
# Specifies the source association name used by <tt>has_many :through</tt> queries.
-
# Only use it if the name cannot be inferred from the association.
-
# <tt>has_many :subscribers, :through => :subscriptions</tt> will look for either <tt>:subscribers</tt> or
-
# <tt>:subscriber</tt> on Subscription, unless a <tt>:source</tt> is given.
-
# [:source_type]
-
# Specifies type of the source association used by <tt>has_many :through</tt> queries where the source
-
# association is a polymorphic +belongs_to+.
-
# [:validate]
-
# If +false+, don't validate the associated objects when saving the parent object. true by default.
-
# [:autosave]
-
# If true, always save the associated objects or destroy them if marked for destruction,
-
# when saving the parent object. If false, never save or destroy the associated objects.
-
# By default, only save associated objects that are new records. This option is implemented as a
-
# before_save callback. Because callbacks are run in the order they are defined, associated objects
-
# may need to be explicitly saved in any user-defined before_save callbacks.
-
#
-
# Note that <tt>accepts_nested_attributes_for</tt> sets <tt>:autosave</tt> to <tt>true</tt>.
-
# [:inverse_of]
-
# Specifies the name of the <tt>belongs_to</tt> association on the associated object
-
# that is the inverse of this <tt>has_many</tt> association. Does not work in combination
-
# with <tt>:through</tt> or <tt>:as</tt> options.
-
# See ActiveRecord::Associations::ClassMethods's overview on Bi-directional associations for more detail.
-
#
-
# Option examples:
-
# has_many :comments, -> { order "posted_on" }
-
# has_many :comments, -> { includes :author }
-
# has_many :people, -> { where("deleted = 0").order("name") }, class_name: "Person"
-
# has_many :tracks, -> { order "position" }, dependent: :destroy
-
# has_many :comments, dependent: :nullify
-
# has_many :tags, as: :taggable
-
# has_many :reports, -> { readonly }
-
# has_many :subscribers, through: :subscriptions, source: :user
-
1
def has_many(name, scope = nil, options = {}, &extension)
-
315
Builder::HasMany.build(self, name, scope, options, &extension)
-
end
-
-
# Specifies a one-to-one association with another class. This method should only be used
-
# if the other class contains the foreign key. If the current class contains the foreign key,
-
# then you should use +belongs_to+ instead. See also ActiveRecord::Associations::ClassMethods's overview
-
# on when to use has_one and when to use belongs_to.
-
#
-
# The following methods for retrieval and query of a single associated object will be added:
-
#
-
# [association(force_reload = false)]
-
# Returns the associated object. +nil+ is returned if none is found.
-
# [association=(associate)]
-
# Assigns the associate object, extracts the primary key, sets it as the foreign key,
-
# and saves the associate object.
-
# [build_association(attributes = {})]
-
# Returns a new object of the associated type that has been instantiated
-
# with +attributes+ and linked to this object through a foreign key, but has not
-
# yet been saved.
-
# [create_association(attributes = {})]
-
# Returns a new object of the associated type that has been instantiated
-
# with +attributes+, linked to this object through a foreign key, and that
-
# has already been saved (if it passed the validation).
-
# [create_association!(attributes = {})]
-
# Does the same as <tt>create_association</tt>, but raises <tt>ActiveRecord::RecordInvalid</tt>
-
# if the record is invalid.
-
#
-
# (+association+ is replaced with the symbol passed as the first argument, so
-
# <tt>has_one :manager</tt> would add among others <tt>manager.nil?</tt>.)
-
#
-
# === Example
-
#
-
# An Account class declares <tt>has_one :beneficiary</tt>, which will add:
-
# * <tt>Account#beneficiary</tt> (similar to <tt>Beneficiary.first(:conditions => "account_id = #{id}")</tt>)
-
# * <tt>Account#beneficiary=(beneficiary)</tt> (similar to <tt>beneficiary.account_id = account.id; beneficiary.save</tt>)
-
# * <tt>Account#build_beneficiary</tt> (similar to <tt>Beneficiary.new("account_id" => id)</tt>)
-
# * <tt>Account#create_beneficiary</tt> (similar to <tt>b = Beneficiary.new("account_id" => id); b.save; b</tt>)
-
# * <tt>Account#create_beneficiary!</tt> (similar to <tt>b = Beneficiary.new("account_id" => id); b.save!; b</tt>)
-
#
-
# === Options
-
#
-
# The declaration can also include an options hash to specialize the behavior of the association.
-
#
-
# Options are:
-
# [:class_name]
-
# Specify the class name of the association. Use it only if that name can't be inferred
-
# from the association name. So <tt>has_one :manager</tt> will by default be linked to the Manager class, but
-
# if the real class name is Person, you'll have to specify it with this option.
-
# [:dependent]
-
# Controls what happens to the associated object when
-
# its owner is destroyed:
-
#
-
# * <tt>:destroy</tt> causes the associated object to also be destroyed
-
# * <tt>:delete</tt> causes the asssociated object to be deleted directly from the database (so callbacks will not execute)
-
# * <tt>:nullify</tt> causes the foreign key to be set to +NULL+. Callbacks are not executed.
-
# * <tt>:restrict_with_exception</tt> causes an exception to be raised if there is an associated record
-
# * <tt>:restrict_with_error</tt> causes an error to be added to the owner if there is an associated object
-
# [:foreign_key]
-
# Specify the foreign key used for the association. By default this is guessed to be the name
-
# of this class in lower-case and "_id" suffixed. So a Person class that makes a +has_one+ association
-
# will use "person_id" as the default <tt>:foreign_key</tt>.
-
# [:primary_key]
-
# Specify the method that returns the primary key used for the association. By default this is +id+.
-
# [:as]
-
# Specifies a polymorphic interface (See <tt>belongs_to</tt>).
-
# [:through]
-
# Specifies a Join Model through which to perform the query. Options for <tt>:class_name</tt>,
-
# <tt>:primary_key</tt>, and <tt>:foreign_key</tt> are ignored, as the association uses the
-
# source reflection. You can only use a <tt>:through</tt> query through a <tt>has_one</tt>
-
# or <tt>belongs_to</tt> association on the join model.
-
# [:source]
-
# Specifies the source association name used by <tt>has_one :through</tt> queries.
-
# Only use it if the name cannot be inferred from the association.
-
# <tt>has_one :favorite, :through => :favorites</tt> will look for a
-
# <tt>:favorite</tt> on Favorite, unless a <tt>:source</tt> is given.
-
# [:source_type]
-
# Specifies type of the source association used by <tt>has_one :through</tt> queries where the source
-
# association is a polymorphic +belongs_to+.
-
# [:validate]
-
# If +false+, don't validate the associated object when saving the parent object. +false+ by default.
-
# [:autosave]
-
# If true, always save the associated object or destroy it if marked for destruction,
-
# when saving the parent object. If false, never save or destroy the associated object.
-
# By default, only save the associated object if it's a new record.
-
#
-
# Note that <tt>accepts_nested_attributes_for</tt> sets <tt>:autosave</tt> to <tt>true</tt>.
-
# [:inverse_of]
-
# Specifies the name of the <tt>belongs_to</tt> association on the associated object
-
# that is the inverse of this <tt>has_one</tt> association. Does not work in combination
-
# with <tt>:through</tt> or <tt>:as</tt> options.
-
# See ActiveRecord::Associations::ClassMethods's overview on Bi-directional associations for more detail.
-
#
-
# Option examples:
-
# has_one :credit_card, :dependent => :destroy # destroys the associated credit card
-
# has_one :credit_card, :dependent => :nullify # updates the associated records foreign
-
# # key value to NULL rather than destroying it
-
# has_one :last_comment, -> { order 'posted_on' }, :class_name => "Comment"
-
# has_one :project_manager, -> { where role: 'project_manager' }, :class_name => "Person"
-
# has_one :attachment, as: :attachable
-
# has_one :boss, readonly: :true
-
# has_one :club, through: :membership
-
# has_one :primary_address, -> { where primary: true }, through: :addressables, source: :addressable
-
1
def has_one(name, scope = nil, options = {})
-
84
Builder::HasOne.build(self, name, scope, options)
-
end
-
-
# Specifies a one-to-one association with another class. This method should only be used
-
# if this class contains the foreign key. If the other class contains the foreign key,
-
# then you should use +has_one+ instead. See also ActiveRecord::Associations::ClassMethods's overview
-
# on when to use +has_one+ and when to use +belongs_to+.
-
#
-
# Methods will be added for retrieval and query for a single associated object, for which
-
# this object holds an id:
-
#
-
# [association(force_reload = false)]
-
# Returns the associated object. +nil+ is returned if none is found.
-
# [association=(associate)]
-
# Assigns the associate object, extracts the primary key, and sets it as the foreign key.
-
# [build_association(attributes = {})]
-
# Returns a new object of the associated type that has been instantiated
-
# with +attributes+ and linked to this object through a foreign key, but has not yet been saved.
-
# [create_association(attributes = {})]
-
# Returns a new object of the associated type that has been instantiated
-
# with +attributes+, linked to this object through a foreign key, and that
-
# has already been saved (if it passed the validation).
-
# [create_association!(attributes = {})]
-
# Does the same as <tt>create_association</tt>, but raises <tt>ActiveRecord::RecordInvalid</tt>
-
# if the record is invalid.
-
#
-
# (+association+ is replaced with the symbol passed as the first argument, so
-
# <tt>belongs_to :author</tt> would add among others <tt>author.nil?</tt>.)
-
#
-
# === Example
-
#
-
# A Post class declares <tt>belongs_to :author</tt>, which will add:
-
# * <tt>Post#author</tt> (similar to <tt>Author.find(author_id)</tt>)
-
# * <tt>Post#author=(author)</tt> (similar to <tt>post.author_id = author.id</tt>)
-
# * <tt>Post#build_author</tt> (similar to <tt>post.author = Author.new</tt>)
-
# * <tt>Post#create_author</tt> (similar to <tt>post.author = Author.new; post.author.save; post.author</tt>)
-
# * <tt>Post#create_author!</tt> (similar to <tt>post.author = Author.new; post.author.save!; post.author</tt>)
-
# The declaration can also include an options hash to specialize the behavior of the association.
-
#
-
# === Options
-
#
-
# [:class_name]
-
# Specify the class name of the association. Use it only if that name can't be inferred
-
# from the association name. So <tt>belongs_to :author</tt> will by default be linked to the Author class, but
-
# if the real class name is Person, you'll have to specify it with this option.
-
# [:foreign_key]
-
# Specify the foreign key used for the association. By default this is guessed to be the name
-
# of the association with an "_id" suffix. So a class that defines a <tt>belongs_to :person</tt>
-
# association will use "person_id" as the default <tt>:foreign_key</tt>. Similarly,
-
# <tt>belongs_to :favorite_person, :class_name => "Person"</tt> will use a foreign key
-
# of "favorite_person_id".
-
# [:foreign_type]
-
# Specify the column used to store the associated object's type, if this is a polymorphic
-
# association. By default this is guessed to be the name of the association with a "_type"
-
# suffix. So a class that defines a <tt>belongs_to :taggable, :polymorphic => true</tt>
-
# association will use "taggable_type" as the default <tt>:foreign_type</tt>.
-
# [:primary_key]
-
# Specify the method that returns the primary key of associated object used for the association.
-
# By default this is id.
-
# [:dependent]
-
# If set to <tt>:destroy</tt>, the associated object is destroyed when this object is. If set to
-
# <tt>:delete</tt>, the associated object is deleted *without* calling its destroy method.
-
# This option should not be specified when <tt>belongs_to</tt> is used in conjunction with
-
# a <tt>has_many</tt> relationship on another class because of the potential to leave
-
# orphaned records behind.
-
# [:counter_cache]
-
# Caches the number of belonging objects on the associate class through the use of +increment_counter+
-
# and +decrement_counter+. The counter cache is incremented when an object of this
-
# class is created and decremented when it's destroyed. This requires that a column
-
# named <tt>#{table_name}_count</tt> (such as +comments_count+ for a belonging Comment class)
-
# is used on the associate class (such as a Post class) - that is the migration for
-
# <tt>#{table_name}_count</tt> is created on the associate class (such that Post.comments_count will
-
# return the count cached, see note below). You can also specify a custom counter
-
# cache column by providing a column name instead of a +true+/+false+ value to this
-
# option (e.g., <tt>:counter_cache => :my_custom_counter</tt>.)
-
# Note: Specifying a counter cache will add it to that model's list of readonly attributes
-
# using +attr_readonly+.
-
# [:polymorphic]
-
# Specify this association is a polymorphic association by passing +true+.
-
# Note: If you've enabled the counter cache, then you may want to add the counter cache attribute
-
# to the +attr_readonly+ list in the associated classes (e.g. <tt>class Post; attr_readonly :comments_count; end</tt>).
-
# [:validate]
-
# If +false+, don't validate the associated objects when saving the parent object. +false+ by default.
-
# [:autosave]
-
# If true, always save the associated object or destroy it if marked for destruction, when
-
# saving the parent object.
-
# If false, never save or destroy the associated object.
-
# By default, only save the associated object if it's a new record.
-
#
-
# Note that <tt>accepts_nested_attributes_for</tt> sets <tt>:autosave</tt> to <tt>true</tt>.
-
# [:touch]
-
# If true, the associated object will be touched (the updated_at/on attributes set to now)
-
# when this record is either saved or destroyed. If you specify a symbol, that attribute
-
# will be updated with the current time in addition to the updated_at/on attribute.
-
# [:inverse_of]
-
# Specifies the name of the <tt>has_one</tt> or <tt>has_many</tt> association on the associated
-
# object that is the inverse of this <tt>belongs_to</tt> association. Does not work in
-
# combination with the <tt>:polymorphic</tt> options.
-
# See ActiveRecord::Associations::ClassMethods's overview on Bi-directional associations for more detail.
-
#
-
# Option examples:
-
# belongs_to :firm, foreign_key: "client_of"
-
# belongs_to :person, primary_key: "name", foreign_key: "person_name"
-
# belongs_to :author, class_name: "Person", foreign_key: "author_id"
-
# belongs_to :valid_coupon, ->(o) { where "discounts > #{o.payments_count}" },
-
# class_name: "Coupon", foreign_key: "coupon_id"
-
# belongs_to :attachable, polymorphic: true
-
# belongs_to :project, readonly: true
-
# belongs_to :post, counter_cache: true
-
# belongs_to :company, touch: true
-
# belongs_to :company, touch: :employees_last_updated_at
-
1
def belongs_to(name, scope = nil, options = {})
-
156
Builder::BelongsTo.build(self, name, scope, options)
-
end
-
-
# Specifies a many-to-many relationship with another class. This associates two classes via an
-
# intermediate join table. Unless the join table is explicitly specified as an option, it is
-
# guessed using the lexical order of the class names. So a join between Developer and Project
-
# will give the default join table name of "developers_projects" because "D" precedes "P" alphabetically.
-
# Note that this precedence is calculated using the <tt><</tt> operator for String. This
-
# means that if the strings are of different lengths, and the strings are equal when compared
-
# up to the shortest length, then the longer string is considered of higher
-
# lexical precedence than the shorter one. For example, one would expect the tables "paper_boxes" and "papers"
-
# to generate a join table name of "papers_paper_boxes" because of the length of the name "paper_boxes",
-
# but it in fact generates a join table name of "paper_boxes_papers". Be aware of this caveat, and use the
-
# custom <tt>:join_table</tt> option if you need to.
-
#
-
# The join table should not have a primary key or a model associated with it. You must manually generate the
-
# join table with a migration such as this:
-
#
-
# class CreateDevelopersProjectsJoinTable < ActiveRecord::Migration
-
# def change
-
# create_table :developers_projects, :id => false do |t|
-
# t.integer :developer_id
-
# t.integer :project_id
-
# end
-
# end
-
# end
-
#
-
# It's also a good idea to add indexes to each of those columns to speed up the joins process.
-
# However, in MySQL it is advised to add a compound index for both of the columns as MySQL only
-
# uses one index per table during the lookup.
-
#
-
# Adds the following methods for retrieval and query:
-
#
-
# [collection(force_reload = false)]
-
# Returns an array of all the associated objects.
-
# An empty array is returned if none are found.
-
# [collection<<(object, ...)]
-
# Adds one or more objects to the collection by creating associations in the join table
-
# (<tt>collection.push</tt> and <tt>collection.concat</tt> are aliases to this method).
-
# Note that this operation instantly fires update sql without waiting for the save or update call on the
-
# parent object.
-
# [collection.delete(object, ...)]
-
# Removes one or more objects from the collection by removing their associations from the join table.
-
# This does not destroy the objects.
-
# [collection.destroy(object, ...)]
-
# Removes one or more objects from the collection by running destroy on each association in the join table, overriding any dependent option.
-
# This does not destroy the objects.
-
# [collection=objects]
-
# Replaces the collection's content by deleting and adding objects as appropriate.
-
# [collection_singular_ids]
-
# Returns an array of the associated objects' ids.
-
# [collection_singular_ids=ids]
-
# Replace the collection by the objects identified by the primary keys in +ids+.
-
# [collection.clear]
-
# Removes every object from the collection. This does not destroy the objects.
-
# [collection.empty?]
-
# Returns +true+ if there are no associated objects.
-
# [collection.size]
-
# Returns the number of associated objects.
-
# [collection.find(id)]
-
# Finds an associated object responding to the +id+ and that
-
# meets the condition that it has to be associated with this object.
-
# Uses the same rules as ActiveRecord::Base.find.
-
# [collection.exists?(...)]
-
# Checks whether an associated object with the given conditions exists.
-
# Uses the same rules as ActiveRecord::Base.exists?.
-
# [collection.build(attributes = {})]
-
# Returns a new object of the collection type that has been instantiated
-
# with +attributes+ and linked to this object through the join table, but has not yet been saved.
-
# [collection.create(attributes = {})]
-
# Returns a new object of the collection type that has been instantiated
-
# with +attributes+, linked to this object through the join table, and that has already been
-
# saved (if it passed the validation).
-
#
-
# (+collection+ is replaced with the symbol passed as the first argument, so
-
# <tt>has_and_belongs_to_many :categories</tt> would add among others <tt>categories.empty?</tt>.)
-
#
-
# === Example
-
#
-
# A Developer class declares <tt>has_and_belongs_to_many :projects</tt>, which will add:
-
# * <tt>Developer#projects</tt>
-
# * <tt>Developer#projects<<</tt>
-
# * <tt>Developer#projects.delete</tt>
-
# * <tt>Developer#projects.destroy</tt>
-
# * <tt>Developer#projects=</tt>
-
# * <tt>Developer#project_ids</tt>
-
# * <tt>Developer#project_ids=</tt>
-
# * <tt>Developer#projects.clear</tt>
-
# * <tt>Developer#projects.empty?</tt>
-
# * <tt>Developer#projects.size</tt>
-
# * <tt>Developer#projects.find(id)</tt>
-
# * <tt>Developer#projects.exists?(...)</tt>
-
# * <tt>Developer#projects.build</tt> (similar to <tt>Project.new("developer_id" => id)</tt>)
-
# * <tt>Developer#projects.create</tt> (similar to <tt>c = Project.new("developer_id" => id); c.save; c</tt>)
-
# The declaration may include an options hash to specialize the behavior of the association.
-
#
-
# === Options
-
#
-
# [:class_name]
-
# Specify the class name of the association. Use it only if that name can't be inferred
-
# from the association name. So <tt>has_and_belongs_to_many :projects</tt> will by default be linked to the
-
# Project class, but if the real class name is SuperProject, you'll have to specify it with this option.
-
# [:join_table]
-
# Specify the name of the join table if the default based on lexical order isn't what you want.
-
# <b>WARNING:</b> If you're overwriting the table name of either class, the +table_name+ method
-
# MUST be declared underneath any +has_and_belongs_to_many+ declaration in order to work.
-
# [:foreign_key]
-
# Specify the foreign key used for the association. By default this is guessed to be the name
-
# of this class in lower-case and "_id" suffixed. So a Person class that makes
-
# a +has_and_belongs_to_many+ association to Project will use "person_id" as the
-
# default <tt>:foreign_key</tt>.
-
# [:association_foreign_key]
-
# Specify the foreign key used for the association on the receiving side of the association.
-
# By default this is guessed to be the name of the associated class in lower-case and "_id" suffixed.
-
# So if a Person class makes a +has_and_belongs_to_many+ association to Project,
-
# the association will use "project_id" as the default <tt>:association_foreign_key</tt>.
-
# [:readonly]
-
# If true, all the associated objects are readonly through the association.
-
# [:validate]
-
# If +false+, don't validate the associated objects when saving the parent object. +true+ by default.
-
# [:autosave]
-
# If true, always save the associated objects or destroy them if marked for destruction, when
-
# saving the parent object.
-
# If false, never save or destroy the associated objects.
-
# By default, only save associated objects that are new records.
-
#
-
# Note that <tt>accepts_nested_attributes_for</tt> sets <tt>:autosave</tt> to <tt>true</tt>.
-
#
-
# Option examples:
-
# has_and_belongs_to_many :projects
-
# has_and_belongs_to_many :projects, -> { includes :milestones, :manager }
-
# has_and_belongs_to_many :nations, class_name: "Country"
-
# has_and_belongs_to_many :categories, join_table: "prods_cats"
-
# has_and_belongs_to_many :categories, -> { readonly }
-
1
def has_and_belongs_to_many(name, scope = nil, options = {}, &extension)
-
63
Builder::HasAndBelongsToMany.build(self, name, scope, options, &extension)
-
end
-
end
-
end
-
end
-
1
require 'active_support/core_ext/string/conversions'
-
-
1
module ActiveRecord
-
1
module Associations
-
# Keeps track of table aliases for ActiveRecord::Associations::ClassMethods::JoinDependency and
-
# ActiveRecord::Associations::ThroughAssociationScope
-
1
class AliasTracker # :nodoc:
-
1
attr_reader :aliases, :table_joins, :connection
-
-
# table_joins is an array of arel joins which might conflict with the aliases we assign here
-
1
def initialize(connection = Base.connection, table_joins = [])
-
10414
@aliases = Hash.new { |h,k| h[k] = initial_count_for(k) }
-
4332
@table_joins = table_joins
-
4332
@connection = connection
-
end
-
-
1
def aliased_table_for(table_name, aliased_name = nil)
-
4635
table_alias = aliased_name_for(table_name, aliased_name)
-
-
4635
if table_alias == table_name
-
4517
Arel::Table.new(table_name)
-
else
-
118
Arel::Table.new(table_name).alias(table_alias)
-
end
-
end
-
-
1
def aliased_name_for(table_name, aliased_name = nil)
-
6089
aliased_name ||= table_name
-
-
6089
if aliases[table_name].zero?
-
# If it's zero, we can have our table_name
-
5964
aliases[table_name] = 1
-
5964
table_name
-
else
-
# Otherwise, we need to use an alias
-
125
aliased_name = connection.table_alias_for(aliased_name)
-
-
# Update the count
-
125
aliases[aliased_name] += 1
-
-
125
if aliases[aliased_name] > 1
-
18
"#{truncate(aliased_name)}_#{aliases[aliased_name]}"
-
else
-
107
aliased_name
-
end
-
end
-
end
-
-
1
private
-
-
1
def initial_count_for(name)
-
6082
return 0 if Arel::Table === table_joins
-
-
# quoted_name should be downcased as some database adapters (Oracle) return quoted name in uppercase
-
6029
quoted_name = connection.quote_table_name(name).downcase
-
-
6029
counts = table_joins.map do |join|
-
863
if join.is_a?(Arel::Nodes::StringJoin)
-
# Table names + table aliases
-
29
join.left.downcase.scan(
-
/join(?:\s+\w+)?\s+(\S+\s+)?#{quoted_name}\son/
-
).size
-
else
-
834
join.left.table_name == name ? 1 : 0
-
end
-
end
-
-
6029
counts.sum
-
end
-
-
1
def truncate(name)
-
18
name.slice(0, connection.table_alias_length - 2)
-
end
-
end
-
end
-
end
-
1
require 'active_support/core_ext/array/wrap'
-
-
1
module ActiveRecord
-
1
module Associations
-
# = Active Record Associations
-
#
-
# This is the root class of all associations ('+ Foo' signifies an included module Foo):
-
#
-
# Association
-
# SingularAssociation
-
# HasOneAssociation
-
# HasOneThroughAssociation + ThroughAssociation
-
# BelongsToAssociation
-
# BelongsToPolymorphicAssociation
-
# CollectionAssociation
-
# HasAndBelongsToManyAssociation
-
# HasManyAssociation
-
# HasManyThroughAssociation + ThroughAssociation
-
1
class Association #:nodoc:
-
1
attr_reader :owner, :target, :reflection
-
-
1
delegate :options, :to => :reflection
-
-
1
def initialize(owner, reflection)
-
4494
reflection.check_validity!
-
-
4486
@owner, @reflection = owner, reflection
-
-
4486
reset
-
4486
reset_scope
-
end
-
-
# Returns the name of the table of the related class:
-
#
-
# post.comments.aliased_table_name # => "comments"
-
#
-
1
def aliased_table_name
-
1
klass.table_name
-
end
-
-
# Resets the \loaded flag to +false+ and sets the \target to +nil+.
-
1
def reset
-
5433
@loaded = false
-
5433
@target = nil
-
5433
@stale_state = nil
-
end
-
-
# Reloads the \target and returns +self+ on success.
-
1
def reload
-
614
reset
-
614
reset_scope
-
614
load_target
-
614
self unless target.nil?
-
end
-
-
# Has the \target been already \loaded?
-
1
def loaded?
-
12940
@loaded
-
end
-
-
# Asserts the \target has been loaded setting the \loaded flag to +true+.
-
1
def loaded!
-
5801
@loaded = true
-
5801
@stale_state = stale_state
-
end
-
-
# The target is stale if the target no longer points to the record(s) that the
-
# relevant foreign_key(s) refers to. If stale, the association accessor method
-
# on the owner will reload the target. It's up to subclasses to implement the
-
# state_state method if relevant.
-
#
-
# Note that if the target has not been loaded, it is not considered stale.
-
1
def stale_target?
-
4839
loaded? && @stale_state != stale_state
-
end
-
-
# Sets the target of this association to <tt>\target</tt>, and the \loaded flag to +true+.
-
1
def target=(target)
-
1447
@target = target
-
1447
loaded!
-
end
-
-
1
def scope
-
6023
target_scope.merge(association_scope)
-
end
-
-
1
def scoped
-
ActiveSupport::Deprecation.warn "#scoped is deprecated. use #scope instead."
-
scope
-
end
-
-
# The scope for this association.
-
#
-
# Note that the association_scope is merged into the target_scope only when the
-
# scoped method is called. This is because at that point the call may be surrounded
-
# by scope.scoping { ... } or with_scope { ... } etc, which affects the scope which
-
# actually gets built.
-
1
def association_scope
-
7470
if klass
-
7470
@association_scope ||= AssociationScope.new(self).scope
-
end
-
end
-
-
1
def reset_scope
-
5319
@association_scope = nil
-
end
-
-
# Set the inverse association, if possible
-
1
def set_inverse_instance(record)
-
5257
if record && invertible_for?(record)
-
70
inverse = record.association(inverse_reflection_for(record).name)
-
70
inverse.target = owner
-
end
-
end
-
-
# This class of the target. belongs_to polymorphic overrides this to look at the
-
# polymorphic_type field on the owner.
-
1
def klass
-
30927
reflection.klass
-
end
-
-
# Can be overridden (i.e. in ThroughAssociation) to merge in other scopes (i.e. the
-
# through association's scope)
-
1
def target_scope
-
6023
klass.all
-
end
-
-
# Loads the \target if needed and returns it.
-
#
-
# This method is abstract in the sense that it relies on +find_target+,
-
# which is expected to be provided by descendants.
-
#
-
# If the \target is already \loaded it is just returned. Thus, you can call
-
# +load_target+ unconditionally to get the \target.
-
#
-
# ActiveRecord::RecordNotFound is rescued within the method, and it is
-
# not reraised. The proxy is \reset and +nil+ is the return value.
-
1
def load_target
-
1034
@target = find_target if (@stale_state && stale_target?) || find_target?
-
-
1034
loaded! unless loaded?
-
1034
target
-
rescue ActiveRecord::RecordNotFound
-
reset
-
end
-
-
1
def interpolate(sql, record = nil)
-
50
if sql.respond_to?(:to_proc)
-
32
owner.send(:instance_exec, record, &sql)
-
else
-
18
sql
-
end
-
end
-
-
# We can't dump @reflection since it contains the scope proc
-
1
def marshal_dump
-
32
ivars = (instance_variables - [:@reflection]).map { |name| [name, instance_variable_get(name)] }
-
5
[@reflection.name, ivars]
-
end
-
-
1
def marshal_load(data)
-
5
reflection_name, ivars = data
-
32
ivars.each { |name, val| instance_variable_set(name, val) }
-
5
@reflection = @owner.class.reflect_on_association(reflection_name)
-
end
-
-
1
private
-
-
1
def find_target?
-
2615
!loaded? && (!owner.new_record? || foreign_key_present?) && klass
-
end
-
-
1
def creation_attributes
-
435
attributes = {}
-
-
435
if (reflection.macro == :has_one || reflection.macro == :has_many) && !options[:through]
-
435
attributes[reflection.foreign_key] = owner[reflection.active_record_primary_key]
-
-
435
if reflection.options[:as]
-
23
attributes[reflection.type] = owner.class.base_class.name
-
end
-
end
-
-
435
attributes
-
end
-
-
# Sets the owner attributes on the given record
-
1
def set_owner_attributes(record)
-
893
creation_attributes.each { |key, value| record[key] = value }
-
end
-
-
# Should be true if there is a foreign key present on the owner which
-
# references the target. This is used to determine whether we can load
-
# the target if the owner is currently a new record (and therefore
-
# without a key).
-
#
-
# Currently implemented by belongs_to (vanilla and polymorphic) and
-
# has_one/has_many :through associations which go through a belongs_to
-
1
def foreign_key_present?
-
49
false
-
end
-
-
# Raises ActiveRecord::AssociationTypeMismatch unless +record+ is of
-
# the kind of the class of the associated objects. Meant to be used as
-
# a sanity check when you are about to assign an associated record.
-
1
def raise_on_type_mismatch(record)
-
937
unless record.is_a?(reflection.klass) || record.is_a?(reflection.class_name.constantize)
-
13
message = "#{reflection.class_name}(##{reflection.klass.object_id}) expected, got #{record.class}(##{record.class.object_id})"
-
13
raise ActiveRecord::AssociationTypeMismatch, message
-
end
-
end
-
-
# Can be redefined by subclasses, notably polymorphic belongs_to
-
# The record parameter is necessary to support polymorphic inverses as we must check for
-
# the association in the specific class of the record.
-
1
def inverse_reflection_for(record)
-
3521
reflection.inverse_of
-
end
-
-
# Is this association invertible? Can be redefined by subclasses.
-
1
def invertible_for?(record)
-
2582
inverse_reflection_for(record)
-
end
-
-
# This should be implemented to return the values of the relevant key(s) on the owner,
-
# so that when stale_state is different from the value stored on the last find_target,
-
# the target is stale.
-
#
-
# This is only relevant to certain associations, which is why it returns nil by default.
-
1
def stale_state
-
end
-
-
1
def build_record(attributes)
-
793
reflection.build_association(attributes) do |record|
-
793
attributes = create_scope.except(*(record.changed - [reflection.foreign_key]))
-
793
record.assign_attributes(attributes)
-
end
-
end
-
end
-
end
-
end
-
1
module ActiveRecord
-
1
module Associations
-
1
class AssociationScope #:nodoc:
-
1
include JoinHelper
-
-
1
attr_reader :association, :alias_tracker
-
-
1
delegate :klass, :owner, :reflection, :interpolate, :to => :association
-
1
delegate :chain, :scope_chain, :options, :source_options, :active_record, :to => :reflection
-
-
1
def initialize(association)
-
2878
@association = association
-
2878
@alias_tracker = AliasTracker.new klass.connection
-
end
-
-
1
def scope
-
2878
scope = klass.unscoped
-
2878
scope.merge! eval_scope(klass, reflection.scope) if reflection.scope
-
2878
add_constraints(scope)
-
end
-
-
1
private
-
-
1
def column_for(table_name, column_name)
-
3151
columns = alias_tracker.connection.schema_cache.columns_hash[table_name]
-
3151
columns[column_name]
-
end
-
-
1
def bind_value(scope, column, value)
-
3151
substitute = alias_tracker.connection.substitute_at(
-
column, scope.bind_values.length)
-
3151
scope.bind_values += [[column, value]]
-
3151
substitute
-
end
-
-
1
def bind(scope, table_name, column_name, value)
-
3151
column = column_for table_name, column_name
-
3151
bind_value scope, column, value
-
end
-
-
1
def add_constraints(scope)
-
2878
tables = construct_tables
-
-
2878
chain.each_with_index do |reflection, i|
-
3396
table, foreign_table = tables.shift, tables.first
-
-
3396
if reflection.source_macro == :has_and_belongs_to_many
-
469
join_table = tables.shift
-
-
469
scope = scope.joins(join(
-
join_table,
-
table[reflection.association_primary_key].
-
eq(join_table[reflection.association_foreign_key])
-
))
-
-
469
table, foreign_table = join_table, tables.first
-
end
-
-
3396
if reflection.source_macro == :belongs_to
-
770
if reflection.options[:polymorphic]
-
43
key = reflection.association_primary_key(klass)
-
else
-
727
key = reflection.association_primary_key
-
end
-
-
770
foreign_key = reflection.foreign_key
-
else
-
2626
key = reflection.foreign_key
-
2626
foreign_key = reflection.active_record_primary_key
-
end
-
-
3396
if reflection == chain.last
-
2878
bind_val = bind scope, table.table_name, key.to_s, owner[foreign_key]
-
2878
scope = scope.where(table[key].eq(bind_val))
-
-
2878
if reflection.type
-
273
value = owner.class.base_class.name
-
273
bind_val = bind scope, table.table_name, reflection.type.to_s, value
-
273
scope = scope.where(table[reflection.type].eq(bind_val))
-
end
-
else
-
518
constraint = table[key].eq(foreign_table[foreign_key])
-
-
518
if reflection.type
-
32
type = chain[i + 1].klass.base_class.name
-
32
constraint = constraint.and(table[reflection.type].eq(type))
-
end
-
-
518
scope = scope.joins(join(foreign_table, constraint))
-
end
-
-
# Exclude the scope of the association itself, because that
-
# was already merged in the #scope method.
-
3396
(scope_chain[i] - [self.reflection.scope]).each do |scope_chain_item|
-
198
item = eval_scope(reflection.klass, scope_chain_item)
-
-
198
scope.includes! item.includes_values
-
198
scope.where_values += item.where_values
-
end
-
end
-
-
2878
scope
-
end
-
-
1
def alias_suffix
-
3865
reflection.name
-
end
-
-
1
def table_name_for(reflection)
-
3396
if reflection == self.reflection
-
# If this is a polymorphic belongs_to, we want to get the klass from the
-
# association because it depends on the polymorphic_type attribute of
-
# the owner
-
2878
klass.table_name
-
else
-
518
reflection.table_name
-
end
-
end
-
-
1
def eval_scope(klass, scope)
-
1132
if scope.is_a?(Relation)
-
6
scope
-
else
-
1126
klass.unscoped.instance_exec(owner, &scope)
-
end
-
end
-
end
-
end
-
end
-
1
module ActiveRecord
-
# = Active Record Belongs To Associations
-
1
module Associations
-
1
class BelongsToAssociation < SingularAssociation #:nodoc:
-
-
1
def handle_dependency
-
8
target.send(options[:dependent]) if load_target
-
end
-
-
1
def replace(record)
-
254
raise_on_type_mismatch(record) if record
-
-
252
update_counters(record)
-
252
replace_keys(record)
-
252
set_inverse_instance(record)
-
-
250
@updated = true if record
-
-
250
self.target = record
-
end
-
-
1
def reset
-
1667
super
-
1667
@updated = false
-
end
-
-
1
def updated?
-
191
@updated
-
end
-
-
1
private
-
-
1
def find_target?
-
608
!loaded? && foreign_key_present? && klass
-
end
-
-
1
def update_counters(record)
-
252
counter_cache_name = reflection.counter_cache_column
-
-
252
if counter_cache_name && owner.persisted? && different_target?(record)
-
10
if record
-
7
record.class.increment_counter(counter_cache_name, record.id)
-
end
-
-
10
if foreign_key_present?
-
7
klass.decrement_counter(counter_cache_name, target_id)
-
end
-
end
-
end
-
-
# Checks whether record is different to the current target, without loading it
-
1
def different_target?(record)
-
record.nil? && owner[reflection.foreign_key] ||
-
13
record && record.id != owner[reflection.foreign_key]
-
end
-
-
1
def replace_keys(record)
-
252
if record
-
244
owner[reflection.foreign_key] = record[reflection.association_primary_key(record.class)]
-
else
-
8
owner[reflection.foreign_key] = nil
-
end
-
end
-
-
1
def foreign_key_present?
-
395
owner[reflection.foreign_key]
-
end
-
-
# NOTE - for now, we're only supporting inverse setting from belongs_to back onto
-
# has_one associations.
-
1
def invertible_for?(record)
-
1161
inverse = inverse_reflection_for(record)
-
1159
inverse && inverse.macro == :has_one
-
end
-
-
1
def target_id
-
7
if options[:primary_key]
-
2
owner.send(reflection.name).try(:id)
-
else
-
5
owner[reflection.foreign_key]
-
end
-
end
-
-
1
def stale_state
-
2793
owner[reflection.foreign_key] && owner[reflection.foreign_key].to_s
-
end
-
end
-
end
-
end
-
1
module ActiveRecord
-
# = Active Record Belongs To Polymorphic Association
-
1
module Associations
-
1
class BelongsToPolymorphicAssociation < BelongsToAssociation #:nodoc:
-
1
def klass
-
308
type = owner[reflection.foreign_type]
-
308
type.presence && type.constantize
-
end
-
-
1
private
-
-
1
def replace_keys(record)
-
28
super
-
28
owner[reflection.foreign_type] = record && record.class.base_class.name
-
end
-
-
1
def different_target?(record)
-
1
super || record.class != klass
-
end
-
-
1
def inverse_reflection_for(record)
-
292
reflection.polymorphic_inverse_of(record.class)
-
end
-
-
1
def raise_on_type_mismatch(record)
-
# A polymorphic association cannot have a type mismatch, by definition
-
end
-
-
1
def stale_state
-
662
foreign_key = super
-
662
foreign_key && [foreign_key.to_s, owner[reflection.foreign_type].to_s]
-
end
-
end
-
end
-
end
-
1
module ActiveRecord::Associations::Builder
-
1
class Association #:nodoc:
-
1
class << self
-
1
attr_accessor :valid_options
-
end
-
-
1
self.valid_options = [:class_name, :foreign_key, :validate]
-
-
1
attr_reader :model, :name, :scope, :options, :reflection
-
-
1
def self.build(*args, &block)
-
618
new(*args, &block).build
-
end
-
-
1
def initialize(model, name, scope, options)
-
621
@model = model
-
621
@name = name
-
-
621
if scope.is_a?(Hash)
-
@scope = nil
-
@options = scope
-
else
-
621
@scope = scope
-
621
@options = options
-
end
-
-
621
if @scope && @scope.arity == 0
-
123
prev_scope = @scope
-
952
@scope = proc { instance_exec(&prev_scope) }
-
end
-
end
-
-
1
def mixin
-
2272
@model.generated_feature_methods
-
end
-
-
2
include Module.new { def build; end }
-
-
1
def build
-
618
validate_options
-
617
define_accessors
-
617
configure_dependency if options[:dependent]
-
615
@reflection = model.create_reflection(macro, name, scope, options, model)
-
615
super # provides an extension point
-
615
@reflection
-
end
-
-
1
def macro
-
raise NotImplementedError
-
end
-
-
1
def valid_options
-
618
Association.valid_options
-
end
-
-
1
def validate_options
-
618
options.assert_valid_keys(valid_options)
-
end
-
-
1
def define_accessors
-
617
define_readers
-
617
define_writers
-
end
-
-
1
def define_readers
-
617
mixin.class_eval <<-CODE, __FILE__, __LINE__ + 1
-
def #{name}(*args)
-
association(:#{name}).reader(*args)
-
end
-
CODE
-
end
-
-
1
def define_writers
-
617
mixin.class_eval <<-CODE, __FILE__, __LINE__ + 1
-
def #{name}=(value)
-
association(:#{name}).writer(value)
-
end
-
CODE
-
end
-
-
1
def configure_dependency
-
59
unless valid_dependent_options.include? options[:dependent]
-
2
raise ArgumentError, "The :dependent option must be one of #{valid_dependent_options}, but is :#{options[:dependent]}"
-
end
-
-
57
if options[:dependent] == :restrict
-
4
ActiveSupport::Deprecation.warn(
-
"The :restrict option is deprecated. Please use :restrict_with_exception instead, which " \
-
"provides the same functionality."
-
)
-
end
-
-
57
mixin.class_eval <<-CODE, __FILE__, __LINE__ + 1
-
def #{macro}_dependent_for_#{name}
-
association(:#{name}).handle_dependency
-
end
-
CODE
-
-
57
model.before_destroy "#{macro}_dependent_for_#{name}"
-
end
-
-
1
def valid_dependent_options
-
raise NotImplementedError
-
end
-
end
-
end
-
1
module ActiveRecord::Associations::Builder
-
1
class BelongsTo < SingularAssociation #:nodoc:
-
1
def macro
-
158
:belongs_to
-
end
-
-
1
def valid_options
-
156
super + [:foreign_type, :polymorphic, :touch]
-
end
-
-
1
def constructable?
-
156
!options[:polymorphic]
-
end
-
-
1
def build
-
156
reflection = super
-
154
add_counter_cache_callbacks(reflection) if options[:counter_cache]
-
154
add_touch_callbacks(reflection) if options[:touch]
-
154
reflection
-
end
-
-
1
def add_counter_cache_callbacks(reflection)
-
16
cache_column = reflection.counter_cache_column
-
-
16
mixin.class_eval <<-CODE, __FILE__, __LINE__ + 1
-
def belongs_to_counter_cache_after_create_for_#{name}
-
record = #{name}
-
record.class.increment_counter(:#{cache_column}, record.id) unless record.nil?
-
end
-
-
def belongs_to_counter_cache_before_destroy_for_#{name}
-
unless marked_for_destruction?
-
record = #{name}
-
record.class.decrement_counter(:#{cache_column}, record.id) unless record.nil?
-
end
-
end
-
CODE
-
-
16
model.after_create "belongs_to_counter_cache_after_create_for_#{name}"
-
16
model.before_destroy "belongs_to_counter_cache_before_destroy_for_#{name}"
-
-
16
klass = reflection.class_name.safe_constantize
-
16
klass.attr_readonly cache_column if klass && klass.respond_to?(:attr_readonly)
-
end
-
-
1
def add_touch_callbacks(reflection)
-
5
mixin.class_eval <<-CODE, __FILE__, __LINE__ + 1
-
def belongs_to_touch_after_save_or_destroy_for_#{name}
-
record = #{name}
-
-
unless record.nil?
-
record.touch #{options[:touch].inspect if options[:touch] != true}
-
end
-
end
-
CODE
-
-
5
model.after_save "belongs_to_touch_after_save_or_destroy_for_#{name}"
-
5
model.after_touch "belongs_to_touch_after_save_or_destroy_for_#{name}"
-
5
model.after_destroy "belongs_to_touch_after_save_or_destroy_for_#{name}"
-
end
-
-
1
def valid_dependent_options
-
6
[:destroy, :delete]
-
end
-
end
-
end
-
1
require 'active_record/associations'
-
-
1
module ActiveRecord::Associations::Builder
-
1
class CollectionAssociation < Association #:nodoc:
-
-
1
CALLBACKS = [:before_add, :after_add, :before_remove, :after_remove]
-
-
1
def valid_options
-
378
super + [:table_name, :finder_sql, :counter_sql, :before_add, :after_add, :before_remove, :after_remove]
-
end
-
-
1
attr_reader :block_extension, :extension_module
-
-
1
def initialize(*args, &extension)
-
381
super(*args)
-
381
@block_extension = extension
-
end
-
-
1
def build
-
378
show_deprecation_warnings
-
378
wrap_block_extension
-
378
reflection = super
-
1885
CALLBACKS.each { |callback_name| define_callback(callback_name) }
-
377
reflection
-
end
-
-
1
def writable?
-
true
-
end
-
-
1
def show_deprecation_warnings
-
378
[:finder_sql, :counter_sql].each do |name|
-
756
if options.include? name
-
21
ActiveSupport::Deprecation.warn("The :#{name} association option is deprecated. Please find an alternative (such as using scopes).")
-
end
-
end
-
end
-
-
1
def wrap_block_extension
-
381
if block_extension
-
8
@extension_module = mod = Module.new(&block_extension)
-
8
silence_warnings do
-
8
model.parent.const_set(extension_module_name, mod)
-
end
-
-
8
prev_scope = @scope
-
-
8
if prev_scope
-
2
@scope = proc { |owner| instance_exec(owner, &prev_scope).extending(mod) }
-
else
-
544
@scope = proc { extending(mod) }
-
end
-
end
-
end
-
-
1
def extension_module_name
-
8
@extension_module_name ||= "#{model.name.demodulize}#{name.to_s.camelize}AssociationExtension"
-
end
-
-
1
def define_callback(callback_name)
-
1508
full_callback_name = "#{callback_name}_for_#{name}"
-
-
# TODO : why do i need method_defined? I think its because of the inheritance chain
-
1508
model.class_attribute full_callback_name.to_sym unless model.method_defined?(full_callback_name)
-
1508
model.send("#{full_callback_name}=", Array(options[callback_name.to_sym]))
-
end
-
-
1
def define_readers
-
377
super
-
-
377
mixin.class_eval <<-CODE, __FILE__, __LINE__ + 1
-
def #{name.to_s.singularize}_ids
-
association(:#{name}).ids_reader
-
end
-
CODE
-
end
-
-
1
def define_writers
-
377
super
-
-
377
mixin.class_eval <<-CODE, __FILE__, __LINE__ + 1
-
def #{name.to_s.singularize}_ids=(ids)
-
association(:#{name}).ids_writer(ids)
-
end
-
CODE
-
end
-
end
-
end
-
1
module ActiveRecord::Associations::Builder
-
1
class HasAndBelongsToMany < CollectionAssociation #:nodoc:
-
1
def macro
-
63
:has_and_belongs_to_many
-
end
-
-
1
def valid_options
-
63
super + [:join_table, :association_foreign_key, :delete_sql, :insert_sql]
-
end
-
-
1
def build
-
63
reflection = super
-
63
define_destroy_hook
-
63
reflection
-
end
-
-
1
def show_deprecation_warnings
-
63
super
-
-
63
[:delete_sql, :insert_sql].each do |name|
-
126
if options.include? name
-
3
ActiveSupport::Deprecation.warn("The :#{name} association option is deprecated. Please find an alternative (such as using has_many :through).")
-
end
-
end
-
end
-
-
1
def define_destroy_hook
-
63
name = self.name
-
63
model.send(:include, Module.new {
-
63
class_eval <<-RUBY, __FILE__, __LINE__ + 1
-
def destroy_associations
-
association(:#{name}).delete_all
-
super
-
end
-
RUBY
-
})
-
end
-
end
-
end
-
1
module ActiveRecord::Associations::Builder
-
1
class HasMany < CollectionAssociation #:nodoc:
-
1
def macro
-
400
:has_many
-
end
-
-
1
def valid_options
-
315
super + [:primary_key, :dependent, :as, :through, :source, :source_type, :inverse_of, :counter_cache]
-
end
-
-
1
def valid_dependent_options
-
43
[:destroy, :delete_all, :nullify, :restrict, :restrict_with_error, :restrict_with_exception]
-
end
-
end
-
end
-
1
module ActiveRecord::Associations::Builder
-
1
class HasOne < SingularAssociation #:nodoc:
-
1
def macro
-
108
:has_one
-
end
-
-
1
def valid_options
-
84
valid = super + [:order, :as]
-
84
valid += [:through, :source, :source_type] if options[:through]
-
84
valid
-
end
-
-
1
def constructable?
-
84
!options[:through]
-
end
-
-
1
def configure_dependency
-
12
super unless options[:through]
-
end
-
-
1
def valid_dependent_options
-
12
[:destroy, :delete, :nullify, :restrict, :restrict_with_error, :restrict_with_exception]
-
end
-
end
-
end
-
1
module ActiveRecord::Associations::Builder
-
1
class SingularAssociation < Association #:nodoc:
-
1
def valid_options
-
240
super + [:remote, :dependent, :counter_cache, :primary_key, :inverse_of]
-
end
-
-
1
def constructable?
-
true
-
end
-
-
1
def define_accessors
-
240
super
-
240
define_constructors if constructable?
-
end
-
-
1
def define_constructors
-
206
mixin.class_eval <<-CODE, __FILE__, __LINE__ + 1
-
def build_#{name}(*args, &block)
-
association(:#{name}).build(*args, &block)
-
end
-
-
def create_#{name}(*args, &block)
-
association(:#{name}).create(*args, &block)
-
end
-
-
def create_#{name}!(*args, &block)
-
association(:#{name}).create!(*args, &block)
-
end
-
CODE
-
end
-
end
-
end
-
1
module ActiveRecord
-
1
module Associations
-
# = Active Record Association Collection
-
#
-
# CollectionAssociation is an abstract class that provides common stuff to
-
# ease the implementation of association proxies that represent
-
# collections. See the class hierarchy in AssociationProxy.
-
#
-
# CollectionAssociation:
-
# HasAndBelongsToManyAssociation => has_and_belongs_to_many
-
# HasManyAssociation => has_many
-
# HasManyThroughAssociation + ThroughAssociation => has_many :through
-
#
-
# CollectionAssociation class provides common methods to the collections
-
# defined by +has_and_belongs_to_many+, +has_many+ or +has_many+ with
-
# +:through association+ option.
-
#
-
# You need to be careful with assumptions regarding the target: The proxy
-
# does not fetch records from the database until it needs them, but new
-
# ones created with +build+ are added to the target. So, the target may be
-
# non-empty and still lack children waiting to be read from the database.
-
# If you look directly to the database you cannot assume that's the entire
-
# collection because new records may have been added to the target, etc.
-
#
-
# If you need to work on all current children, new and existing records,
-
# +load_target+ and the +loaded+ flag are your friends.
-
1
class CollectionAssociation < Association #:nodoc:
-
-
# Implements the reader method, e.g. foo.items for Foo.has_many :items
-
1
def reader(force_reload = false)
-
3152
if force_reload
-
182
klass.uncached { reload }
-
elsif stale_target?
-
1
reload
-
end
-
-
3152
CollectionProxy.new(self)
-
end
-
-
# Implements the writer method, e.g. foo.items= for Foo.has_many :items
-
1
def writer(records)
-
38
replace(records)
-
end
-
-
# Implements the ids reader method, e.g. foo.item_ids for Foo.has_many :items
-
1
def ids_reader
-
29
if loaded? || options[:finder_sql]
-
12
load_target.map do |record|
-
20
record.send(reflection.association_primary_key)
-
end
-
else
-
17
column = "#{reflection.quoted_table_name}.#{reflection.association_primary_key}"
-
17
scope.pluck(column)
-
end
-
end
-
-
# Implements the ids writer method, e.g. foo.item_ids= for Foo.has_many :items
-
1
def ids_writer(ids)
-
22
pk_column = reflection.primary_key_column
-
54
ids = Array(ids).reject { |id| id.blank? }
-
50
ids.map! { |i| pk_column.type_cast(i) }
-
48
replace(klass.find(ids).index_by { |r| r.id }.values_at(*ids))
-
end
-
-
1
def reset
-
3054
super
-
3054
@target = []
-
end
-
-
1
def select(select = nil)
-
7
if block_given?
-
15
load_target.select.each { |e| yield e }
-
else
-
4
scope.select(select)
-
end
-
end
-
-
1
def find(*args)
-
30
if block_given?
-
load_target.find(*args) { |*block_args| yield(*block_args) }
-
else
-
30
if options[:finder_sql]
-
8
find_by_scan(*args)
-
else
-
22
scope.find(*args)
-
end
-
end
-
end
-
-
1
def first(*args)
-
132
first_or_last(:first, *args)
-
end
-
-
1
def last(*args)
-
42
first_or_last(:last, *args)
-
end
-
-
1
def build(attributes = {}, &block)
-
246
if attributes.is_a?(Array)
-
12
attributes.collect { |attr| build(attr, &block) }
-
else
-
242
add_to_target(build_record(attributes)) do |record|
-
241
yield(record) if block_given?
-
end
-
end
-
end
-
-
1
def create(attributes = {}, &block)
-
146
create_record(attributes, &block)
-
end
-
-
1
def create!(attributes = {}, &block)
-
208
create_record(attributes, true, &block)
-
end
-
-
# Add +records+ to this association. Returns +self+ so method calls may
-
# be chained. Since << flattens its argument list and inserts each record,
-
# +push+ and +concat+ behave identically.
-
1
def concat(*records)
-
184
load_target if owner.new_record?
-
-
184
if owner.new_record?
-
62
concat_records(records)
-
else
-
244
transaction { concat_records(records) }
-
end
-
end
-
-
# Starts a transaction in the association class's database connection.
-
#
-
# class Author < ActiveRecord::Base
-
# has_many :books
-
# end
-
#
-
# Author.first.books.transaction do
-
# # same effect as calling Book.transaction
-
# end
-
1
def transaction(*args)
-
658
reflection.klass.transaction(*args) do
-
658
yield
-
end
-
end
-
-
# Remove all records from this association.
-
#
-
# See delete for more info.
-
1
def delete_all
-
325
delete(:all).tap do
-
323
reset
-
323
loaded!
-
end
-
end
-
-
# Destroy all the records from this association.
-
#
-
# See destroy for more info.
-
1
def destroy_all
-
8
destroy(load_target).tap do
-
8
reset
-
8
loaded!
-
end
-
end
-
-
# Calculate sum using SQL, not Enumerable.
-
1
def sum(*args)
-
if block_given?
-
scope.sum(*args) { |*block_args| yield(*block_args) }
-
else
-
scope.sum(*args)
-
end
-
end
-
-
# Count all records using SQL. If the +:counter_sql+ or +:finder_sql+ option is set for the
-
# association, it will be used for the query. Otherwise, construct options and pass them with
-
# scope to the target class's +count+.
-
1
def count(column_name = nil, count_options = {})
-
198
column_name, count_options = nil, column_name if column_name.is_a?(Hash)
-
-
198
if options[:counter_sql] || options[:finder_sql]
-
11
unless count_options.blank?
-
2
raise ArgumentError, "If finder_sql/counter_sql is used then options cannot be passed"
-
end
-
-
9
reflection.klass.count_by_sql(custom_counter_sql)
-
else
-
187
if association_scope.uniq_value
-
# This is needed because 'SELECT count(DISTINCT *)..' is not valid SQL.
-
4
column_name ||= reflection.klass.primary_key
-
4
count_options[:distinct] = true
-
end
-
-
187
value = scope.count(column_name, count_options)
-
-
187
limit = options[:limit]
-
187
offset = options[:offset]
-
-
187
if limit || offset
-
[ [value - offset.to_i, 0].max, limit.to_i ].min
-
else
-
187
value
-
end
-
end
-
end
-
-
# Removes +records+ from this association calling +before_remove+ and
-
# +after_remove+ callbacks.
-
#
-
# This method is abstract in the sense that +delete_records+ has to be
-
# provided by descendants. Note this method does not imply the records
-
# are actually removed from the database, that depends precisely on
-
# +delete_records+. They are in any case removed from the collection.
-
1
def delete(*records)
-
427
dependent = options[:dependent]
-
-
427
if records.first == :all
-
325
if loaded? || dependent == :destroy
-
185
delete_or_destroy(load_target, dependent)
-
else
-
140
delete_records(:all, dependent)
-
end
-
else
-
206
records = find(records) if records.any? { |record| record.kind_of?(Fixnum) || record.kind_of?(String) }
-
102
delete_or_destroy(records, dependent)
-
end
-
end
-
-
# Destroy +records+ and remove them from this association calling
-
# +before_remove+ and +after_remove+ callbacks.
-
#
-
# Note that this method will _always_ remove records from the database
-
# ignoring the +:dependent+ option.
-
1
def destroy(*records)
-
102
records = find(records) if records.any? { |record| record.kind_of?(Fixnum) || record.kind_of?(String) }
-
50
delete_or_destroy(records, :destroy)
-
end
-
-
# Returns the size of the collection by executing a SELECT COUNT(*)
-
# query if the collection hasn't been loaded, and calling
-
# <tt>collection.size</tt> if it has.
-
#
-
# If the collection has been already loaded +size+ and +length+ are
-
# equivalent. If not and you are going to need the records anyway
-
# +length+ will take one less query. Otherwise +size+ is more efficient.
-
#
-
# This method is abstract in the sense that it relies on
-
# +count_records+, which is a method descendants have to provide.
-
1
def size
-
272
if !find_target? || loaded?
-
169
if association_scope.uniq_value
-
10
target.uniq.size
-
else
-
159
target.size
-
end
-
103
elsif !loaded? && !association_scope.group_values.empty?
-
5
load_target.size
-
98
elsif !loaded? && !association_scope.uniq_value && target.is_a?(Array)
-
95
unsaved_records = target.select { |r| r.new_record? }
-
87
unsaved_records.size + count_records
-
else
-
11
count_records
-
end
-
end
-
-
# Returns the size of the collection calling +size+ on the target.
-
#
-
# If the collection has been already loaded +length+ and +size+ are
-
# equivalent. If not and you are going to need the records anyway this
-
# method will take one less query. Otherwise +size+ is more efficient.
-
1
def length
-
166
load_target.size
-
end
-
-
# Returns true if the collection is empty.
-
#
-
# If the collection has been loaded or the <tt>:counter_sql</tt> option
-
# is provided, it is equivalent to <tt>collection.size.zero?</tt>. If the
-
# collection has not been loaded, it is equivalent to
-
# <tt>collection.exists?</tt>. If the collection has not already been
-
# loaded and you are going to fetch the records anyway it is better to
-
# check <tt>collection.length.zero?</tt>.
-
1
def empty?
-
58
if loaded? || options[:counter_sql]
-
26
size.zero?
-
else
-
32
!scope.exists?
-
end
-
end
-
-
# Returns true if the collections is not empty.
-
# Equivalent to +!collection.empty?+.
-
1
def any?
-
14
if block_given?
-
28
load_target.any? { |*block_args| yield(*block_args) }
-
else
-
3
!empty?
-
end
-
end
-
-
# Returns true if the collection has more than 1 record.
-
# Equivalent to +collection.size > 1+.
-
1
def many?
-
6
if block_given?
-
3
load_target.many? { |*block_args| yield(*block_args) }
-
else
-
5
size > 1
-
end
-
end
-
-
1
def uniq
-
4
seen = {}
-
4
load_target.find_all do |record|
-
9
seen[record.id] = true unless seen.key?(record.id)
-
end
-
end
-
-
# Replace this collection with +other_array+. This will perform a diff
-
# and delete/add only records that have changed.
-
1
def replace(other_array)
-
139
other_array.each { |val| raise_on_type_mismatch(val) }
-
61
original_target = load_target.dup
-
-
61
if owner.new_record?
-
25
replace_records(other_array, original_target)
-
else
-
72
transaction { replace_records(other_array, original_target) }
-
end
-
end
-
-
1
def include?(record)
-
92
if record.is_a?(reflection.klass)
-
90
if record.new_record?
-
7
include_in_memory?(record)
-
else
-
83
load_target if options[:finder_sql]
-
83
loaded? ? target.include?(record) : scope.exists?(record)
-
end
-
else
-
2
false
-
end
-
end
-
-
1
def load_target
-
1923
if find_target?
-
786
@target = merge_target_lists(find_target, target)
-
end
-
-
1923
loaded!
-
1923
target
-
end
-
-
1
def add_to_target(record)
-
827
callback(:before_add, record)
-
826
yield(record) if block_given?
-
-
818
if association_scope.uniq_value && index = @target.index(record)
-
4
@target[index] = record
-
else
-
814
@target << record
-
end
-
-
818
callback(:after_add, record)
-
818
set_inverse_instance(record)
-
-
818
record
-
end
-
-
1
def scope(opts = {})
-
5254
scope = super()
-
5254
scope.none! if opts.fetch(:nullify, true) && null_scope?
-
5254
scope
-
end
-
-
1
def null_scope?
-
2102
owner.new_record? && !foreign_key_present?
-
end
-
-
1
private
-
-
1
def custom_counter_sql
-
24
if options[:counter_sql]
-
18
interpolate(options[:counter_sql])
-
else
-
# replace the SELECT clause with COUNT(SELECTS), preserving any hints within /* ... */
-
6
interpolate(options[:finder_sql]).sub(/SELECT\b(\/\*.*?\*\/ )?(.*)\bFROM\b/im) do
-
6
count_with = $2.to_s
-
6
count_with = '*' if count_with.blank? || count_with =~ /,/ || count_with =~ /\.\*/
-
6
"SELECT #{$1}COUNT(#{count_with}) FROM"
-
end
-
end
-
end
-
-
1
def custom_finder_sql
-
11
interpolate(options[:finder_sql])
-
end
-
-
1
def find_target
-
629
records =
-
if options[:finder_sql]
-
11
reflection.klass.find_by_sql(custom_finder_sql)
-
else
-
618
scope.to_a
-
end
-
-
1533
records.each { |record| set_inverse_instance(record) }
-
629
records
-
end
-
-
# We have some records loaded from the database (persisted) and some that are
-
# in-memory (memory). The same record may be represented in the persisted array
-
# and in the memory array.
-
#
-
# So the task of this method is to merge them according to the following rules:
-
#
-
# * The final array must not have duplicates
-
# * The order of the persisted array is to be preserved
-
# * Any changes made to attributes on objects in the memory array are to be preserved
-
# * Otherwise, attributes should have the value found in the database
-
1
def merge_target_lists(persisted, memory)
-
786
return persisted if memory.empty?
-
140
return memory if persisted.empty?
-
-
134
persisted.map! do |record|
-
248
if mem_record = memory.delete(record)
-
-
217
((record.attribute_names & mem_record.attribute_names) - mem_record.changes.keys).each do |name|
-
1411
mem_record[name] = record[name]
-
end
-
-
217
mem_record
-
else
-
31
record
-
end
-
end
-
-
134
persisted + memory
-
end
-
-
1
def create_record(attributes, raise = false, &block)
-
356
unless owner.persisted?
-
5
raise ActiveRecord::RecordNotSaved, "You cannot call create unless the parent is saved"
-
end
-
-
351
if attributes.is_a?(Array)
-
3
attributes.collect { |attr| create_record(attr, raise, &block) }
-
else
-
350
transaction do
-
350
add_to_target(build_record(attributes)) do |record|
-
349
yield(record) if block_given?
-
349
insert_record(record, true, raise)
-
end
-
end
-
end
-
end
-
-
# Do the relevant stuff to insert the given record into the association collection.
-
1
def insert_record(record, validate = true, raise = false)
-
raise NotImplementedError
-
end
-
-
1
def create_scope
-
590
scope.scope_for_create.stringify_keys
-
end
-
-
1
def delete_or_destroy(records, method)
-
337
records = records.flatten
-
561
records.each { |record| raise_on_type_mismatch(record) }
-
555
existing_records = records.reject { |r| r.new_record? }
-
-
334
if existing_records.empty?
-
184
remove_records(existing_records, records, method)
-
else
-
300
transaction { remove_records(existing_records, records, method) }
-
end
-
end
-
-
1
def remove_records(existing_records, records, method)
-
555
records.each { |record| callback(:before_remove, record) }
-
-
334
delete_records(existing_records, method) if existing_records.any?
-
525
records.each { |record| target.delete(record) }
-
-
525
records.each { |record| callback(:after_remove, record) }
-
end
-
-
# Delete the given records from the association, using one of the methods :destroy,
-
# :delete_all or :nullify (or nil, in which case a default is used).
-
1
def delete_records(records, method)
-
raise NotImplementedError
-
end
-
-
1
def replace_records(new_target, original_target)
-
61
delete(target - new_target)
-
-
56
unless concat(new_target - target)
-
1
@target = original_target
-
1
raise RecordNotSaved, "Failed to replace #{reflection.name} because one or more of the " \
-
"new records could not be saved."
-
end
-
-
54
target
-
end
-
-
1
def concat_records(records)
-
183
result = true
-
-
183
records.flatten.each do |record|
-
204
raise_on_type_mismatch(record)
-
199
add_to_target(record) do |r|
-
198
result &&= insert_record(record) unless owner.new_record?
-
end
-
end
-
-
171
result && records
-
end
-
-
1
def callback(method, record)
-
2069
callbacks_for(method).each do |callback|
-
139
case callback
-
when Symbol
-
55
owner.send(callback, record)
-
when Proc
-
84
callback.call(owner, record)
-
else
-
callback.send(method, owner, record)
-
end
-
end
-
end
-
-
1
def callbacks_for(callback_name)
-
2069
full_callback_name = "#{callback_name}_for_#{reflection.name}"
-
2069
owner.class.send(full_callback_name.to_sym) || []
-
end
-
-
# Should we deal with assoc.first or assoc.last by issuing an independent query to
-
# the database, or by getting the target, and then taking the first/last item from that?
-
#
-
# If the args is just a non-empty options hash, go to the database.
-
#
-
# Otherwise, go to the database only if none of the following are true:
-
# * target already loaded
-
# * owner is new record
-
# * custom :finder_sql exists
-
# * target contains new or changed record(s)
-
# * the first arg is an integer (which indicates the number of records to be returned)
-
1
def fetch_first_or_last_using_find?(args)
-
174
if args.first.is_a?(Hash)
-
true
-
else
-
!(loaded? ||
-
174
owner.new_record? ||
-
options[:finder_sql] ||
-
17
target.any? { |record| record.new_record? || record.changed? } ||
-
174
args.first.kind_of?(Integer))
-
end
-
end
-
-
1
def include_in_memory?(record)
-
7
if reflection.is_a?(ActiveRecord::Reflection::ThroughReflection)
-
owner.send(reflection.through_reflection.name).any? { |source|
-
3
target = source.send(reflection.source_reflection.name)
-
3
target.respond_to?(:include?) ? target.include?(record) : target == record
-
3
} || target.include?(record)
-
else
-
4
target.include?(record)
-
end
-
end
-
-
# If using a custom finder_sql, #find scans the entire collection.
-
1
def find_by_scan(*args)
-
8
expects_array = args.first.kind_of?(Array)
-
19
ids = args.flatten.compact.map{ |arg| arg.to_i }.uniq
-
-
8
if ids.size == 1
-
7
id = ids.first
-
14
record = load_target.detect { |r| id == r.id }
-
7
expects_array ? [ record ] : record
-
else
-
11
load_target.select { |r| ids.include?(r.id) }
-
end
-
end
-
-
# Fetches the first/last using SQL if possible, otherwise from the target array.
-
1
def first_or_last(type, *args)
-
174
args.shift if args.first.is_a?(Hash) && args.first.empty?
-
-
174
collection = fetch_first_or_last_using_find?(args) ? scope : load_target
-
174
collection.send(type, *args).tap do |record|
-
174
set_inverse_instance record if record.is_a? ActiveRecord::Base
-
end
-
end
-
end
-
end
-
end
-
1
module ActiveRecord
-
1
module Associations
-
# Association proxies in Active Record are middlemen between the object that
-
# holds the association, known as the <tt>@owner</tt>, and the actual associated
-
# object, known as the <tt>@target</tt>. The kind of association any proxy is
-
# about is available in <tt>@reflection</tt>. That's an instance of the class
-
# ActiveRecord::Reflection::AssociationReflection.
-
#
-
# For example, given
-
#
-
# class Blog < ActiveRecord::Base
-
# has_many :posts
-
# end
-
#
-
# blog = Blog.first
-
#
-
# the association proxy in <tt>blog.posts</tt> has the object in +blog+ as
-
# <tt>@owner</tt>, the collection of its posts as <tt>@target</tt>, and
-
# the <tt>@reflection</tt> object represents a <tt>:has_many</tt> macro.
-
#
-
# This class delegates unknown methods to <tt>@target</tt> via
-
# <tt>method_missing</tt>.
-
#
-
# The <tt>@target</tt> object is not \loaded until needed. For example,
-
#
-
# blog.posts.count
-
#
-
# is computed directly through SQL and does not trigger by itself the
-
# instantiation of the actual post records.
-
1
class CollectionProxy < Relation
-
1
delegate(*(ActiveRecord::Calculations.public_instance_methods - [:count]), to: :scope)
-
-
1
def initialize(association) #:nodoc:
-
3152
@association = association
-
3152
super association.klass, association.klass.arel_table
-
3152
merge! association.scope(nullify: false)
-
end
-
-
1
def target
-
273
@association.target
-
end
-
-
1
def load_target
-
966
@association.load_target
-
end
-
-
# Returns +true+ if the association has been loaded, otherwise +false+.
-
#
-
# person.pets.loaded? # => false
-
# person.pets
-
# person.pets.loaded? # => true
-
1
def loaded?
-
71
@association.loaded?
-
end
-
-
# Works in two ways.
-
#
-
# *First:* Specify a subset of fields to be selected from the result set.
-
#
-
# class Person < ActiveRecord::Base
-
# has_many :pets
-
# end
-
#
-
# person.pets
-
# # => [
-
# # #<Pet id: 1, name: "Fancy-Fancy", person_id: 1>,
-
# # #<Pet id: 2, name: "Spook", person_id: 1>,
-
# # #<Pet id: 3, name: "Choo-Choo", person_id: 1>
-
# # ]
-
#
-
# person.pets.select(:name)
-
# # => [
-
# # #<Pet id: nil, name: "Fancy-Fancy">,
-
# # #<Pet id: nil, name: "Spook">,
-
# # #<Pet id: nil, name: "Choo-Choo">
-
# # ]
-
#
-
# person.pets.select([:id, :name])
-
# # => [
-
# # #<Pet id: 1, name: "Fancy-Fancy">,
-
# # #<Pet id: 2, name: "Spook">,
-
# # #<Pet id: 3, name: "Choo-Choo">
-
# # ]
-
#
-
# Be careful because this also means you’re initializing a model
-
# object with only the fields that you’ve selected. If you attempt
-
# to access a field that is not in the initialized record you’ll
-
# receive:
-
#
-
# person.pets.select(:name).first.person_id
-
# # => ActiveModel::MissingAttributeError: missing attribute: person_id
-
#
-
# *Second:* You can pass a block so it can be used just like Array#select.
-
# This build an array of objects from the database for the scope,
-
# converting them into an array and iterating through them using
-
# Array#select.
-
#
-
# person.pets.select { |pet| pet.name =~ /oo/ }
-
# # => [
-
# # #<Pet id: 2, name: "Spook", person_id: 1>,
-
# # #<Pet id: 3, name: "Choo-Choo", person_id: 1>
-
# # ]
-
#
-
# person.pets.select(:name) { |pet| pet.name =~ /oo/ }
-
# # => [
-
# # #<Pet id: 2, name: "Spook">,
-
# # #<Pet id: 3, name: "Choo-Choo">
-
# # ]
-
1
def select(select = nil, &block)
-
7
@association.select(select, &block)
-
end
-
-
# Finds an object in the collection responding to the +id+. Uses the same
-
# rules as <tt>ActiveRecord::Base.find</tt>. Returns <tt>ActiveRecord::RecordNotFound</tt>
-
# error if the object can not be found.
-
#
-
# class Person < ActiveRecord::Base
-
# has_many :pets
-
# end
-
#
-
# person.pets
-
# # => [
-
# # #<Pet id: 1, name: "Fancy-Fancy", person_id: 1>,
-
# # #<Pet id: 2, name: "Spook", person_id: 1>,
-
# # #<Pet id: 3, name: "Choo-Choo", person_id: 1>
-
# # ]
-
#
-
# person.pets.find(1) # => #<Pet id: 1, name: "Fancy-Fancy", person_id: 1>
-
# person.pets.find(4) # => ActiveRecord::RecordNotFound: Couldn't find Pet with id=4
-
#
-
# person.pets.find(2) { |pet| pet.name.downcase! }
-
# # => #<Pet id: 2, name: "fancy-fancy", person_id: 1>
-
#
-
# person.pets.find(2, 3)
-
# # => [
-
# # #<Pet id: 2, name: "Spook", person_id: 1>,
-
# # #<Pet id: 3, name: "Choo-Choo", person_id: 1>
-
# # ]
-
1
def find(*args, &block)
-
24
@association.find(*args, &block)
-
end
-
-
# Returns the first record, or the first +n+ records, from the collection.
-
# If the collection is empty, the first form returns +nil+, and the second
-
# form returns an empty array.
-
#
-
# class Person < ActiveRecord::Base
-
# has_many :pets
-
# end
-
#
-
# person.pets
-
# # => [
-
# # #<Pet id: 1, name: "Fancy-Fancy", person_id: 1>,
-
# # #<Pet id: 2, name: "Spook", person_id: 1>,
-
# # #<Pet id: 3, name: "Choo-Choo", person_id: 1>
-
# # ]
-
#
-
# person.pets.first # => #<Pet id: 1, name: "Fancy-Fancy", person_id: 1>
-
#
-
# person.pets.first(2)
-
# # => [
-
# # #<Pet id: 1, name: "Fancy-Fancy", person_id: 1>,
-
# # #<Pet id: 2, name: "Spook", person_id: 1>
-
# # ]
-
#
-
# another_person_without.pets # => []
-
# another_person_without.pets.first # => nil
-
# another_person_without.pets.first(3) # => []
-
1
def first(*args)
-
132
@association.first(*args)
-
end
-
-
# Returns the last record, or the last +n+ records, from the collection.
-
# If the collection is empty, the first form returns +nil+, and the second
-
# form returns an empty array.
-
#
-
# class Person < ActiveRecord::Base
-
# has_many :pets
-
# end
-
#
-
# person.pets
-
# # => [
-
# # #<Pet id: 1, name: "Fancy-Fancy", person_id: 1>,
-
# # #<Pet id: 2, name: "Spook", person_id: 1>,
-
# # #<Pet id: 3, name: "Choo-Choo", person_id: 1>
-
# # ]
-
#
-
# person.pets.last # => #<Pet id: 3, name: "Choo-Choo", person_id: 1>
-
#
-
# person.pets.last(2)
-
# # => [
-
# # #<Pet id: 2, name: "Spook", person_id: 1>,
-
# # #<Pet id: 3, name: "Choo-Choo", person_id: 1>
-
# # ]
-
#
-
# another_person_without.pets # => []
-
# another_person_without.pets.last # => nil
-
# another_person_without.pets.last(3) # => []
-
1
def last(*args)
-
42
@association.last(*args)
-
end
-
-
# Returns a new object of the collection type that has been instantiated
-
# with +attributes+ and linked to this object, but have not yet been saved.
-
# You can pass an array of attributes hashes, this will return an array
-
# with the new objects.
-
#
-
# class Person
-
# has_many :pets
-
# end
-
#
-
# person.pets.build
-
# # => #<Pet id: nil, name: nil, person_id: 1>
-
#
-
# person.pets.build(name: 'Fancy-Fancy')
-
# # => #<Pet id: nil, name: "Fancy-Fancy", person_id: 1>
-
#
-
# person.pets.build([{name: 'Spook'}, {name: 'Choo-Choo'}, {name: 'Brain'}])
-
# # => [
-
# # #<Pet id: nil, name: "Spook", person_id: 1>,
-
# # #<Pet id: nil, name: "Choo-Choo", person_id: 1>,
-
# # #<Pet id: nil, name: "Brain", person_id: 1>
-
# # ]
-
#
-
# person.pets.size # => 5 # size of the collection
-
# person.pets.count # => 0 # count from database
-
1
def build(attributes = {}, &block)
-
126
@association.build(attributes, &block)
-
end
-
-
# Returns a new object of the collection type that has been instantiated with
-
# attributes, linked to this object and that has already been saved (if it
-
# passes the validations).
-
#
-
# class Person
-
# has_many :pets
-
# end
-
#
-
# person.pets.create(name: 'Fancy-Fancy')
-
# # => #<Pet id: 1, name: "Fancy-Fancy", person_id: 1>
-
#
-
# person.pets.create([{name: 'Spook'}, {name: 'Choo-Choo'}])
-
# # => [
-
# # #<Pet id: 2, name: "Spook", person_id: 1>,
-
# # #<Pet id: 3, name: "Choo-Choo", person_id: 1>
-
# # ]
-
#
-
# person.pets.size # => 3
-
# person.pets.count # => 3
-
#
-
# person.pets.find(1, 2, 3)
-
# # => [
-
# # #<Pet id: 1, name: "Fancy-Fancy", person_id: 1>,
-
# # #<Pet id: 2, name: "Spook", person_id: 1>,
-
# # #<Pet id: 3, name: "Choo-Choo", person_id: 1>
-
# # ]
-
1
def create(attributes = {}, &block)
-
146
@association.create(attributes, &block)
-
end
-
-
# Like +create+, except that if the record is invalid, raises an exception.
-
#
-
# class Person
-
# has_many :pets
-
# end
-
#
-
# class Pet
-
# validates :name, presence: true
-
# end
-
#
-
# person.pets.create!(name: nil)
-
# # => ActiveRecord::RecordInvalid: Validation failed: Name can't be blank
-
1
def create!(attributes = {}, &block)
-
208
@association.create!(attributes, &block)
-
end
-
-
# Add one or more records to the collection by setting their foreign keys
-
# to the association's primary key. Since << flattens its argument list and
-
# inserts each record, +push+ and +concat+ behave identically. Returns +self+
-
# so method calls may be chained.
-
#
-
# class Person < ActiveRecord::Base
-
# pets :has_many
-
# end
-
#
-
# person.pets.size # => 0
-
# person.pets.concat(Pet.new(name: 'Fancy-Fancy'))
-
# person.pets.concat(Pet.new(name: 'Spook'), Pet.new(name: 'Choo-Choo'))
-
# person.pets.size # => 3
-
#
-
# person.id # => 1
-
# person.pets
-
# # => [
-
# # #<Pet id: 1, name: "Fancy-Fancy", person_id: 1>,
-
# # #<Pet id: 2, name: "Spook", person_id: 1>,
-
# # #<Pet id: 3, name: "Choo-Choo", person_id: 1>
-
# # ]
-
#
-
# person.pets.concat([Pet.new(name: 'Brain'), Pet.new(name: 'Benny')])
-
# person.pets.size # => 5
-
1
def concat(*records)
-
7
@association.concat(*records)
-
end
-
-
# Replace this collection with +other_array+. This will perform a diff
-
# and delete/add only records that have changed.
-
#
-
# class Person < ActiveRecord::Base
-
# has_many :pets
-
# end
-
#
-
# person.pets
-
# # => [#<Pet id: 1, name: "Gorby", group: "cats", person_id: 1>]
-
#
-
# other_pets = [Pet.new(name: 'Puff', group: 'celebrities']
-
#
-
# person.pets.replace(other_pets)
-
#
-
# person.pets
-
# # => [#<Pet id: 2, name: "Puff", group: "celebrities", person_id: 1>]
-
#
-
# If the supplied array has an incorrect association type, it raises
-
# an <tt>ActiveRecord::AssociationTypeMismatch</tt> error:
-
#
-
# person.pets.replace(["doo", "ggie", "gaga"])
-
# # => ActiveRecord::AssociationTypeMismatch: Pet expected, got String
-
1
def replace(other_array)
-
2
@association.replace(other_array)
-
end
-
-
# Deletes all the records from the collection. For +has_many+ associations,
-
# the deletion is done according to the strategy specified by the <tt>:dependent</tt>
-
# option. Returns an array with the deleted records.
-
#
-
# If no <tt>:dependent</tt> option is given, then it will follow the
-
# default strategy. The default strategy is <tt>:nullify</tt>. This
-
# sets the foreign keys to <tt>NULL</tt>. For, +has_many+ <tt>:through</tt>,
-
# the default strategy is +delete_all+.
-
#
-
# class Person < ActiveRecord::Base
-
# has_many :pets # dependent: :nullify option by default
-
# end
-
#
-
# person.pets.size # => 3
-
# person.pets
-
# # => [
-
# # #<Pet id: 1, name: "Fancy-Fancy", person_id: 1>,
-
# # #<Pet id: 2, name: "Spook", person_id: 1>,
-
# # #<Pet id: 3, name: "Choo-Choo", person_id: 1>
-
# # ]
-
#
-
# person.pets.delete_all
-
# # => [
-
# # #<Pet id: 1, name: "Fancy-Fancy", person_id: 1>,
-
# # #<Pet id: 2, name: "Spook", person_id: 1>,
-
# # #<Pet id: 3, name: "Choo-Choo", person_id: 1>
-
# # ]
-
#
-
# person.pets.size # => 0
-
# person.pets # => []
-
#
-
# Pet.find(1, 2, 3)
-
# # => [
-
# # #<Pet id: 1, name: "Fancy-Fancy", person_id: nil>,
-
# # #<Pet id: 2, name: "Spook", person_id: nil>,
-
# # #<Pet id: 3, name: "Choo-Choo", person_id: nil>
-
# # ]
-
#
-
# If it is set to <tt>:destroy</tt> all the objects from the collection
-
# are removed by calling their +destroy+ method. See +destroy+ for more
-
# information.
-
#
-
# class Person < ActiveRecord::Base
-
# has_many :pets, dependent: :destroy
-
# end
-
#
-
# person.pets.size # => 3
-
# person.pets
-
# # => [
-
# # #<Pet id: 1, name: "Fancy-Fancy", person_id: 1>,
-
# # #<Pet id: 2, name: "Spook", person_id: 1>,
-
# # #<Pet id: 3, name: "Choo-Choo", person_id: 1>
-
# # ]
-
#
-
# person.pets.delete_all
-
# # => [
-
# # #<Pet id: 1, name: "Fancy-Fancy", person_id: 1>,
-
# # #<Pet id: 2, name: "Spook", person_id: 1>,
-
# # #<Pet id: 3, name: "Choo-Choo", person_id: 1>
-
# # ]
-
#
-
# Pet.find(1, 2, 3)
-
# # => ActiveRecord::RecordNotFound
-
#
-
# If it is set to <tt>:delete_all</tt>, all the objects are deleted
-
# *without* calling their +destroy+ method.
-
#
-
# class Person < ActiveRecord::Base
-
# has_many :pets, dependent: :delete_all
-
# end
-
#
-
# person.pets.size # => 3
-
# person.pets
-
# # => [
-
# # #<Pet id: 1, name: "Fancy-Fancy", person_id: 1>,
-
# # #<Pet id: 2, name: "Spook", person_id: 1>,
-
# # #<Pet id: 3, name: "Choo-Choo", person_id: 1>
-
# # ]
-
#
-
# person.pets.delete_all
-
# # => [
-
# # #<Pet id: 1, name: "Fancy-Fancy", person_id: 1>,
-
# # #<Pet id: 2, name: "Spook", person_id: 1>,
-
# # #<Pet id: 3, name: "Choo-Choo", person_id: 1>
-
# # ]
-
#
-
# Pet.find(1, 2, 3)
-
# # => ActiveRecord::RecordNotFound
-
1
def delete_all
-
23
@association.delete_all
-
end
-
-
# Deletes the records of the collection directly from the database.
-
# This will _always_ remove the records ignoring the +:dependent+
-
# option.
-
#
-
# class Person < ActiveRecord::Base
-
# has_many :pets
-
# end
-
#
-
# person.pets.size # => 3
-
# person.pets
-
# # => [
-
# # #<Pet id: 1, name: "Fancy-Fancy", person_id: 1>,
-
# # #<Pet id: 2, name: "Spook", person_id: 1>,
-
# # #<Pet id: 3, name: "Choo-Choo", person_id: 1>
-
# # ]
-
#
-
# person.pets.destroy_all
-
#
-
# person.pets.size # => 0
-
# person.pets # => []
-
#
-
# Pet.find(1) # => Couldn't find Pet with id=1
-
1
def destroy_all
-
7
@association.destroy_all
-
end
-
-
# Deletes the +records+ supplied and removes them from the collection. For
-
# +has_many+ associations, the deletion is done according to the strategy
-
# specified by the <tt>:dependent</tt> option. Returns an array with the
-
# deleted records.
-
#
-
# If no <tt>:dependent</tt> option is given, then it will follow the default
-
# strategy. The default strategy is <tt>:nullify</tt>. This sets the foreign
-
# keys to <tt>NULL</tt>. For, +has_many+ <tt>:through</tt>, the default
-
# strategy is +delete_all+.
-
#
-
# class Person < ActiveRecord::Base
-
# has_many :pets # dependent: :nullify option by default
-
# end
-
#
-
# person.pets.size # => 3
-
# person.pets
-
# # => [
-
# # #<Pet id: 1, name: "Fancy-Fancy", person_id: 1>,
-
# # #<Pet id: 2, name: "Spook", person_id: 1>,
-
# # #<Pet id: 3, name: "Choo-Choo", person_id: 1>
-
# # ]
-
#
-
# person.pets.delete(Pet.find(1))
-
# # => [#<Pet id: 1, name: "Fancy-Fancy", person_id: 1>]
-
#
-
# person.pets.size # => 2
-
# person.pets
-
# # => [
-
# # #<Pet id: 2, name: "Spook", person_id: 1>,
-
# # #<Pet id: 3, name: "Choo-Choo", person_id: 1>
-
# # ]
-
#
-
# Pet.find(1)
-
# # => #<Pet id: 1, name: "Fancy-Fancy", person_id: nil>
-
#
-
# If it is set to <tt>:destroy</tt> all the +records+ are removed by calling
-
# their +destroy+ method. See +destroy+ for more information.
-
#
-
# class Person < ActiveRecord::Base
-
# has_many :pets, dependent: :destroy
-
# end
-
#
-
# person.pets.size # => 3
-
# person.pets
-
# # => [
-
# # #<Pet id: 1, name: "Fancy-Fancy", person_id: 1>,
-
# # #<Pet id: 2, name: "Spook", person_id: 1>,
-
# # #<Pet id: 3, name: "Choo-Choo", person_id: 1>
-
# # ]
-
#
-
# person.pets.delete(Pet.find(1), Pet.find(3))
-
# # => [
-
# # #<Pet id: 1, name: "Fancy-Fancy", person_id: 1>,
-
# # #<Pet id: 3, name: "Choo-Choo", person_id: 1>
-
# # ]
-
#
-
# person.pets.size # => 1
-
# person.pets
-
# # => [#<Pet id: 2, name: "Spook", person_id: 1>]
-
#
-
# Pet.find(1, 3)
-
# # => ActiveRecord::RecordNotFound: Couldn't find all Pets with IDs (1, 3)
-
#
-
# If it is set to <tt>:delete_all</tt>, all the +records+ are deleted
-
# *without* calling their +destroy+ method.
-
#
-
# class Person < ActiveRecord::Base
-
# has_many :pets, dependent: :delete_all
-
# end
-
#
-
# person.pets.size # => 3
-
# person.pets
-
# # => [
-
# # #<Pet id: 1, name: "Fancy-Fancy", person_id: 1>,
-
# # #<Pet id: 2, name: "Spook", person_id: 1>,
-
# # #<Pet id: 3, name: "Choo-Choo", person_id: 1>
-
# # ]
-
#
-
# person.pets.delete(Pet.find(1))
-
# # => [#<Pet id: 1, name: "Fancy-Fancy", person_id: 1>]
-
#
-
# person.pets.size # => 2
-
# person.pets
-
# # => [
-
# # #<Pet id: 2, name: "Spook", person_id: 1>,
-
# # #<Pet id: 3, name: "Choo-Choo", person_id: 1>
-
# # ]
-
#
-
# Pet.find(1)
-
# # => ActiveRecord::RecordNotFound: Couldn't find Pet with id=1
-
#
-
# You can pass +Fixnum+ or +String+ values, it finds the records
-
# responding to the +id+ and executes delete on them.
-
#
-
# class Person < ActiveRecord::Base
-
# has_many :pets
-
# end
-
#
-
# person.pets.size # => 3
-
# person.pets
-
# # => [
-
# # #<Pet id: 1, name: "Fancy-Fancy", person_id: 1>,
-
# # #<Pet id: 2, name: "Spook", person_id: 1>,
-
# # #<Pet id: 3, name: "Choo-Choo", person_id: 1>
-
# # ]
-
#
-
# person.pets.delete("1")
-
# # => [#<Pet id: 1, name: "Fancy-Fancy", person_id: 1>]
-
#
-
# person.pets.delete(2, 3)
-
# # => [
-
# # #<Pet id: 2, name: "Spook", person_id: 1>,
-
# # #<Pet id: 3, name: "Choo-Choo", person_id: 1>
-
# # ]
-
1
def delete(*records)
-
41
@association.delete(*records)
-
end
-
-
# Destroys the +records+ supplied and removes them from the collection.
-
# This method will _always_ remove record from the database ignoring
-
# the +:dependent+ option. Returns an array with the removed records.
-
#
-
# class Person < ActiveRecord::Base
-
# has_many :pets
-
# end
-
#
-
# person.pets.size # => 3
-
# person.pets
-
# # => [
-
# # #<Pet id: 1, name: "Fancy-Fancy", person_id: 1>,
-
# # #<Pet id: 2, name: "Spook", person_id: 1>,
-
# # #<Pet id: 3, name: "Choo-Choo", person_id: 1>
-
# # ]
-
#
-
# person.pets.destroy(Pet.find(1))
-
# # => [#<Pet id: 1, name: "Fancy-Fancy", person_id: 1>]
-
#
-
# person.pets.size # => 2
-
# person.pets
-
# # => [
-
# # #<Pet id: 2, name: "Spook", person_id: 1>,
-
# # #<Pet id: 3, name: "Choo-Choo", person_id: 1>
-
# # ]
-
#
-
# person.pets.destroy(Pet.find(2), Pet.find(3))
-
# # => [
-
# # #<Pet id: 2, name: "Spook", person_id: 1>,
-
# # #<Pet id: 3, name: "Choo-Choo", person_id: 1>
-
# # ]
-
#
-
# person.pets.size # => 0
-
# person.pets # => []
-
#
-
# Pet.find(1, 2, 3) # => ActiveRecord::RecordNotFound: Couldn't find all Pets with IDs (1, 2, 3)
-
#
-
# You can pass +Fixnum+ or +String+ values, it finds the records
-
# responding to the +id+ and then deletes them from the database.
-
#
-
# person.pets.size # => 3
-
# person.pets
-
# # => [
-
# # #<Pet id: 4, name: "Benny", person_id: 1>,
-
# # #<Pet id: 5, name: "Brain", person_id: 1>,
-
# # #<Pet id: 6, name: "Boss", person_id: 1>
-
# # ]
-
#
-
# person.pets.destroy("4")
-
# # => #<Pet id: 4, name: "Benny", person_id: 1>
-
#
-
# person.pets.size # => 2
-
# person.pets
-
# # => [
-
# # #<Pet id: 5, name: "Brain", person_id: 1>,
-
# # #<Pet id: 6, name: "Boss", person_id: 1>
-
# # ]
-
#
-
# person.pets.destroy(5, 6)
-
# # => [
-
# # #<Pet id: 5, name: "Brain", person_id: 1>,
-
# # #<Pet id: 6, name: "Boss", person_id: 1>
-
# # ]
-
#
-
# person.pets.size # => 0
-
# person.pets # => []
-
#
-
# Pet.find(4, 5, 6) # => ActiveRecord::RecordNotFound: Couldn't find all Pets with IDs (4, 5, 6)
-
1
def destroy(*records)
-
10
@association.destroy(*records)
-
end
-
-
# Specifies whether the records should be unique or not.
-
#
-
# class Person < ActiveRecord::Base
-
# has_many :pets
-
# end
-
#
-
# person.pets.select(:name)
-
# # => [
-
# # #<Pet name: "Fancy-Fancy">,
-
# # #<Pet name: "Fancy-Fancy">
-
# # ]
-
#
-
# person.pets.select(:name).uniq
-
# # => [#<Pet name: "Fancy-Fancy">]
-
1
def uniq
-
4
@association.uniq
-
end
-
-
# Count all records using SQL.
-
#
-
# class Person < ActiveRecord::Base
-
# has_many :pets
-
# end
-
#
-
# person.pets.count # => 3
-
# person.pets
-
# # => [
-
# # #<Pet id: 1, name: "Fancy-Fancy", person_id: 1>,
-
# # #<Pet id: 2, name: "Spook", person_id: 1>,
-
# # #<Pet id: 3, name: "Choo-Choo", person_id: 1>
-
# # ]
-
1
def count(column_name = nil, options = {})
-
194
@association.count(column_name, options)
-
end
-
-
# Returns the size of the collection. If the collection hasn't been loaded,
-
# it executes a <tt>SELECT COUNT(*)</tt> query.
-
#
-
# class Person < ActiveRecord::Base
-
# has_many :pets
-
# end
-
#
-
# person.pets.size # => 3
-
# # executes something like SELECT COUNT(*) FROM "pets" WHERE "pets"."person_id" = 1
-
#
-
# person.pets # This will execute a SELECT * FROM query
-
# # => [
-
# # #<Pet id: 1, name: "Fancy-Fancy", person_id: 1>,
-
# # #<Pet id: 2, name: "Spook", person_id: 1>,
-
# # #<Pet id: 3, name: "Choo-Choo", person_id: 1>
-
# # ]
-
#
-
# person.pets.size # => 3
-
# # Because the collection is already loaded, this will behave like
-
# # collection.size and no SQL count query is executed.
-
1
def size
-
272
@association.size
-
end
-
-
# Returns the size of the collection calling +size+ on the target.
-
# If the collection has been already loaded, +length+ and +size+ are
-
# equivalent.
-
#
-
# class Person < ActiveRecord::Base
-
# has_many :pets
-
# end
-
#
-
# person.pets.length # => 3
-
# # executes something like SELECT "pets".* FROM "pets" WHERE "pets"."person_id" = 1
-
#
-
# # Because the collection is loaded, you can
-
# # call the collection with no additional queries:
-
# person.pets
-
# # => [
-
# # #<Pet id: 1, name: "Fancy-Fancy", person_id: 1>,
-
# # #<Pet id: 2, name: "Spook", person_id: 1>,
-
# # #<Pet id: 3, name: "Choo-Choo", person_id: 1>
-
# # ]
-
1
def length
-
166
@association.length
-
end
-
-
# Returns +true+ if the collection is empty.
-
#
-
# class Person < ActiveRecord::Base
-
# has_many :pets
-
# end
-
#
-
# person.pets.count # => 1
-
# person.pets.empty? # => false
-
#
-
# person.pets.delete_all
-
#
-
# person.pets.count # => 0
-
# person.pets.empty? # => true
-
1
def empty?
-
52
@association.empty?
-
end
-
-
# Returns +true+ if the collection is not empty.
-
#
-
# class Person < ActiveRecord::Base
-
# has_many :pets
-
# end
-
#
-
# person.pets.count # => 0
-
# person.pets.any? # => false
-
#
-
# person.pets << Pet.new(name: 'Snoop')
-
# person.pets.count # => 0
-
# person.pets.any? # => true
-
#
-
# You can also pass a block to define criteria. The behaviour
-
# is the same, it returns true if the collection based on the
-
# criteria is not empty.
-
#
-
# person.pets
-
# # => [#<Pet name: "Snoop", group: "dogs">]
-
#
-
# person.pets.any? do |pet|
-
# pet.group == 'cats'
-
# end
-
# # => false
-
#
-
# person.pets.any? do |pet|
-
# pet.group == 'dogs'
-
# end
-
# # => true
-
1
def any?(&block)
-
14
@association.any?(&block)
-
end
-
-
# Returns true if the collection has more than one record.
-
# Equivalent to <tt>collection.size > 1</tt>.
-
#
-
# class Person < ActiveRecord::Base
-
# has_many :pets
-
# end
-
#
-
# person.pets.count #=> 1
-
# person.pets.many? #=> false
-
#
-
# person.pets << Pet.new(name: 'Snoopy')
-
# person.pets.count #=> 2
-
# person.pets.many? #=> true
-
#
-
# You can also pass a block to define criteria. The
-
# behaviour is the same, it returns true if the collection
-
# based on the criteria has more than one record.
-
#
-
# person.pets
-
# # => [
-
# # #<Pet name: "Gorby", group: "cats">,
-
# # #<Pet name: "Puff", group: "cats">,
-
# # #<Pet name: "Snoop", group: "dogs">
-
# # ]
-
#
-
# person.pets.many? do |pet|
-
# pet.group == 'dogs'
-
# end
-
# # => false
-
#
-
# person.pets.many? do |pet|
-
# pet.group == 'cats'
-
# end
-
# # => true
-
1
def many?(&block)
-
6
@association.many?(&block)
-
end
-
-
# Returns +true+ if the given object is present in the collection.
-
#
-
# class Person < ActiveRecord::Base
-
# has_many :pets
-
# end
-
#
-
# person.pets # => [#<Pet id: 20, name: "Snoop">]
-
#
-
# person.pets.include?(Pet.find(20)) # => true
-
# person.pets.include?(Pet.find(21)) # => false
-
1
def include?(record)
-
92
@association.include?(record)
-
end
-
-
1
alias_method :new, :build
-
-
1
def proxy_association
-
155
@association
-
end
-
-
# We don't want this object to be put on the scoping stack, because
-
# that could create an infinite loop where we call an @association
-
# method, which gets the current scope, which is this object, which
-
# delegates to @association, and so on.
-
1
def scoping
-
168
@association.scope.scoping { yield }
-
end
-
-
# Returns a <tt>Relation</tt> object for the records in this association
-
1
def scope
-
100
association = @association
-
-
100
@association.scope.extending! do
-
101
define_method(:proxy_association) { association }
-
end
-
end
-
-
# :nodoc:
-
1
alias spawn scope
-
-
# Equivalent to <tt>Array#==</tt>. Returns +true+ if the two arrays
-
# contain the same number of elements and if each element is equal
-
# to the corresponding element in the other array, otherwise returns
-
# +false+.
-
#
-
# class Person < ActiveRecord::Base
-
# has_many :pets
-
# end
-
#
-
# person.pets
-
# # => [
-
# # #<Pet id: 1, name: "Fancy-Fancy", person_id: 1>,
-
# # #<Pet id: 2, name: "Spook", person_id: 1>
-
# # ]
-
#
-
# other = person.pets.to_ary
-
#
-
# person.pets == other
-
# # => true
-
#
-
# other = [Pet.new(id: 1), Pet.new(id: 2)]
-
#
-
# person.pets == other
-
# # => false
-
1
def ==(other)
-
119
load_target == other
-
end
-
-
# Returns a new array of objects from the collection. If the collection
-
# hasn't been loaded, it fetches the records from the database.
-
#
-
# class Person < ActiveRecord::Base
-
# has_many :pets
-
# end
-
#
-
# person.pets
-
# # => [
-
# # #<Pet id: 4, name: "Benny", person_id: 1>,
-
# # #<Pet id: 5, name: "Brain", person_id: 1>,
-
# # #<Pet id: 6, name: "Boss", person_id: 1>
-
# # ]
-
#
-
# other_pets = person.pets.to_ary
-
# # => [
-
# # #<Pet id: 4, name: "Benny", person_id: 1>,
-
# # #<Pet id: 5, name: "Brain", person_id: 1>,
-
# # #<Pet id: 6, name: "Boss", person_id: 1>
-
# # ]
-
#
-
# other_pets.replace([Pet.new(name: 'BooGoo')])
-
#
-
# other_pets
-
# # => [#<Pet id: nil, name: "BooGoo", person_id: 1>]
-
#
-
# person.pets
-
# # This is not affected by replace
-
# # => [
-
# # #<Pet id: 4, name: "Benny", person_id: 1>,
-
# # #<Pet id: 5, name: "Brain", person_id: 1>,
-
# # #<Pet id: 6, name: "Boss", person_id: 1>
-
# # ]
-
1
def to_ary
-
830
load_target.dup
-
end
-
1
alias_method :to_a, :to_ary
-
-
# Adds one or more +records+ to the collection by setting their foreign keys
-
# to the association‘s primary key. Returns +self+, so several appends may be
-
# chained together.
-
#
-
# class Person < ActiveRecord::Base
-
# has_many :pets
-
# end
-
#
-
# person.pets.size # => 0
-
# person.pets << Pet.new(name: 'Fancy-Fancy')
-
# person.pets << [Pet.new(name: 'Spook'), Pet.new(name: 'Choo-Choo')]
-
# person.pets.size # => 3
-
#
-
# person.id # => 1
-
# person.pets
-
# # => [
-
# # #<Pet id: 1, name: "Fancy-Fancy", person_id: 1>,
-
# # #<Pet id: 2, name: "Spook", person_id: 1>,
-
# # #<Pet id: 3, name: "Choo-Choo", person_id: 1>
-
# # ]
-
1
def <<(*records)
-
123
proxy_association.concat(records) && self
-
end
-
1
alias_method :push, :<<
-
-
# Equivalent to +delete_all+. The difference is that returns +self+, instead
-
# of an array with the deleted objects, so methods can be chained. See
-
# +delete_all+ for more information.
-
1
def clear
-
17
delete_all
-
16
self
-
end
-
-
# Reloads the collection from the database. Returns +self+.
-
# Equivalent to <tt>collection(true)</tt>.
-
#
-
# class Person < ActiveRecord::Base
-
# has_many :pets
-
# end
-
#
-
# person.pets # fetches pets from the database
-
# # => [#<Pet id: 1, name: "Snoop", group: "dogs", person_id: 1>]
-
#
-
# person.pets # uses the pets cache
-
# # => [#<Pet id: 1, name: "Snoop", group: "dogs", person_id: 1>]
-
#
-
# person.pets.reload # fetches pets from the database
-
# # => [#<Pet id: 1, name: "Snoop", group: "dogs", person_id: 1>]
-
#
-
# person.pets(true) # fetches pets from the database
-
# # => [#<Pet id: 1, name: "Snoop", group: "dogs", person_id: 1>]
-
1
def reload
-
20
proxy_association.reload
-
20
self
-
end
-
end
-
end
-
end
-
1
module ActiveRecord
-
# = Active Record Has And Belongs To Many Association
-
1
module Associations
-
1
class HasAndBelongsToManyAssociation < CollectionAssociation #:nodoc:
-
1
attr_reader :join_table
-
-
1
def initialize(owner, reflection)
-
698
@join_table = Arel::Table.new(reflection.join_table)
-
698
super
-
end
-
-
1
def insert_record(record, validate = true, raise = false)
-
187
if record.new_record?
-
143
if raise
-
74
record.save!(:validate => validate)
-
else
-
69
return unless record.save(:validate => validate)
-
end
-
end
-
-
186
if options[:insert_sql]
-
owner.connection.insert(interpolate(options[:insert_sql], record))
-
else
-
186
stmt = join_table.compile_insert(
-
join_table[reflection.foreign_key] => owner.id,
-
join_table[reflection.association_foreign_key] => record.id
-
)
-
-
186
owner.connection.insert stmt
-
end
-
-
186
record
-
end
-
-
1
private
-
-
1
def count_records
-
26
load_target.size
-
end
-
-
1
def delete_records(records, method)
-
118
if sql = options[:delete_sql]
-
3
records = load_target if records == :all
-
18
records.each { |record| owner.connection.delete(interpolate(sql, record)) }
-
else
-
115
relation = join_table
-
115
condition = relation[reflection.foreign_key].eq(owner.id)
-
-
115
unless records == :all
-
29
condition = condition.and(
-
relation[reflection.association_foreign_key]
-
36
.in(records.map { |x| x.id }.compact)
-
)
-
end
-
-
115
owner.connection.delete(relation.where(condition).compile_delete)
-
end
-
end
-
-
1
def invertible_for?(record)
-
940
false
-
end
-
end
-
end
-
end
-
1
module ActiveRecord
-
# = Active Record Has Many Association
-
1
module Associations
-
# This is the proxy that handles a has many association.
-
#
-
# If the association has a <tt>:through</tt> option further specialization
-
# is provided by its child HasManyThroughAssociation.
-
1
class HasManyAssociation < CollectionAssociation #:nodoc:
-
-
1
def handle_dependency
-
219
case options[:dependent]
-
when :restrict, :restrict_with_exception
-
2
raise ActiveRecord::DeleteRestrictionError.new(reflection.name) unless empty?
-
-
when :restrict_with_error
-
1
unless empty?
-
1
record = klass.human_attribute_name(reflection.name).downcase
-
1
owner.errors.add(:base, :"restrict_dependent_destroy.many", record: record)
-
1
false
-
end
-
-
else
-
216
if options[:dependent] == :destroy
-
# No point in executing the counter update since we're going to destroy the parent anyway
-
171
load_target.each(&:mark_for_destruction)
-
end
-
-
216
delete_all
-
end
-
end
-
-
1
def insert_record(record, validate = true, raise = false)
-
362
set_owner_attributes(record)
-
-
362
if raise
-
121
record.save!(:validate => validate)
-
else
-
241
record.save(:validate => validate)
-
end
-
end
-
-
1
private
-
-
# Returns the number of records in this collection.
-
#
-
# If the association has a counter cache it gets that value. Otherwise
-
# it will attempt to do a count via SQL, bounded to <tt>:limit</tt> if
-
# there's one. Some configuration options like :group make it impossible
-
# to do an SQL count, in those cases the array count will be used.
-
#
-
# That does not depend on whether the collection has already been loaded
-
# or not. The +size+ method is the one that takes the loaded flag into
-
# account and delegates to +count_records+ if needed.
-
#
-
# If the collection is empty the target is set to an empty array and
-
# the loaded flag is set to true as well.
-
1
def count_records
-
72
count = if has_cached_counter?
-
25
owner.send(:read_attribute, cached_counter_attribute_name)
-
elsif options[:counter_sql] || options[:finder_sql]
-
15
reflection.klass.count_by_sql(custom_counter_sql)
-
else
-
32
scope.count
-
end
-
-
# If there's nothing in the database and @target has no new records
-
# we are certain the current target is an empty array. This is a
-
# documented side-effect of the method that may avoid an extra SELECT.
-
72
@target ||= [] and loaded! if count == 0
-
-
72
[association_scope.limit_value, count].compact.min
-
end
-
-
1
def has_cached_counter?(reflection = reflection)
-
332
owner.attribute_present?(cached_counter_attribute_name(reflection))
-
end
-
-
1
def cached_counter_attribute_name(reflection = reflection)
-
468
options[:counter_cache] || "#{reflection.name}_count"
-
end
-
-
1
def update_counter(difference, reflection = reflection)
-
229
if has_cached_counter?(reflection)
-
35
counter = cached_counter_attribute_name(reflection)
-
35
owner.class.update_counters(owner.id, counter => difference)
-
35
owner[counter] += difference
-
35
owner.changed_attributes.delete(counter) # eww
-
end
-
end
-
-
# This shit is nasty. We need to avoid the following situation:
-
#
-
# * An associated record is deleted via record.destroy
-
# * Hence the callbacks run, and they find a belongs_to on the record with a
-
# :counter_cache options which points back at our owner. So they update the
-
# counter cache.
-
# * In which case, we must make sure to *not* update the counter cache, or else
-
# it will be decremented twice.
-
#
-
# Hence this method.
-
1
def inverse_updates_counter_cache?(reflection = reflection)
-
62
counter_name = cached_counter_attribute_name(reflection)
-
62
reflection.klass.reflect_on_all_associations(:belongs_to).any? { |inverse_reflection|
-
223
inverse_reflection.counter_cache_column == counter_name
-
}
-
end
-
-
# Deletes the records according to the <tt>:dependent</tt> option.
-
1
def delete_records(records, method)
-
124
if method == :destroy
-
127
records.each { |r| r.destroy }
-
55
update_counter(-records.length) unless inverse_updates_counter_cache?
-
else
-
66
if records == :all
-
42
scope = self.scope
-
else
-
71
keys = records.map { |r| r[reflection.association_primary_key] }
-
24
scope = self.scope.where(reflection.association_primary_key => keys)
-
end
-
-
66
if method == :delete_all
-
34
update_counter(-scope.delete_all)
-
else
-
32
update_counter(-scope.update_all(reflection.foreign_key => nil))
-
end
-
end
-
end
-
-
1
def foreign_key_present?
-
160
owner.attribute_present?(reflection.association_primary_key)
-
end
-
end
-
end
-
end
-
-
1
module ActiveRecord
-
# = Active Record Has Many Through Association
-
1
module Associations
-
1
class HasManyThroughAssociation < HasManyAssociation #:nodoc:
-
1
include ThroughAssociation
-
-
1
def initialize(owner, reflection)
-
451
super
-
-
448
@through_records = {}
-
448
@through_association = nil
-
end
-
-
# Returns the size of the collection by executing a SELECT COUNT(*) query if the collection hasn't been
-
# loaded and calling collection.size if it has. If it's more likely than not that the collection does
-
# have a size larger than zero, and you need to fetch that collection afterwards, it'll take one fewer
-
# SELECT query if you use #length.
-
1
def size
-
31
if has_cached_counter?
-
14
owner.send(:read_attribute, cached_counter_attribute_name)
-
17
elsif loaded?
-
13
target.size
-
else
-
4
count
-
end
-
end
-
-
1
def concat(*records)
-
48
unless owner.new_record?
-
39
records.flatten.each do |record|
-
44
raise_on_type_mismatch(record)
-
43
record.save! if record.new_record?
-
end
-
end
-
-
46
super
-
end
-
-
1
def concat_records(records)
-
46
ensure_not_nested
-
-
45
records = super
-
-
41
if owner.new_record? && records
-
9
records.flatten.each do |record|
-
10
build_through_record(record)
-
end
-
end
-
-
41
records
-
end
-
-
1
def insert_record(record, validate = true, raise = false)
-
64
ensure_not_nested
-
-
64
if record.new_record?
-
20
if raise
-
10
record.save!(:validate => validate)
-
else
-
10
return unless record.save(:validate => validate)
-
end
-
end
-
-
62
save_through_record(record)
-
58
update_counter(1)
-
58
record
-
end
-
-
1
private
-
-
1
def through_association
-
181
@through_association ||= owner.association(through_reflection.name)
-
end
-
-
# We temporarily cache through record that has been build, because if we build a
-
# through record in build_record and then subsequently call insert_record, then we
-
# want to use the exact same object.
-
#
-
# However, after insert_record has been called, we clear the cache entry because
-
# we want it to be possible to have multiple instances of the same record in an
-
# association
-
1
def build_through_record(record)
-
82
@through_records[record.object_id] ||= begin
-
74
ensure_mutable
-
-
72
through_record = through_association.build
-
72
through_record.send("#{source_reflection.name}=", record)
-
72
through_record
-
end
-
end
-
-
1
def save_through_record(record)
-
62
build_through_record(record).save!
-
ensure
-
62
@through_records.delete(record.object_id)
-
end
-
-
1
def build_record(attributes)
-
29
ensure_not_nested
-
-
27
record = super(attributes)
-
-
27
inverse = source_reflection.inverse_of
-
27
if inverse
-
10
if inverse.macro == :has_many
-
9
record.send(inverse.name) << build_through_record(record)
-
elsif inverse.macro == :has_one
-
1
record.send("#{inverse.name}=", build_through_record(record))
-
end
-
end
-
-
27
record
-
end
-
-
1
def target_reflection_has_associated_record?
-
157
if through_reflection.macro == :belongs_to && owner[through_reflection.foreign_key].blank?
-
1
false
-
else
-
156
true
-
end
-
end
-
-
1
def update_through_counter?(method)
-
38
case method
-
when :destroy
-
7
!inverse_updates_counter_cache?(through_reflection)
-
when :nullify
-
7
false
-
else
-
24
true
-
end
-
end
-
-
1
def delete_records(records, method)
-
48
ensure_not_nested
-
-
# This is unoptimised; it will load all the target records
-
# even when we just want to delete everything.
-
44
records = load_target if records == :all
-
-
44
scope = through_association.scope
-
44
scope.where! construct_join_attributes(*records)
-
-
39
case method
-
when :destroy
-
7
count = scope.destroy_all.length
-
when :nullify
-
7
count = scope.update_all(source_reflection.foreign_key => nil)
-
else
-
25
count = scope.delete_all
-
end
-
-
39
delete_through_records(records)
-
-
39
if through_reflection.macro == :has_many && update_through_counter?(method)
-
30
update_counter(-count, through_reflection)
-
end
-
-
39
update_counter(-count)
-
end
-
-
1
def through_records_for(record)
-
46
attributes = construct_join_attributes(record)
-
46
candidates = Array.wrap(through_association.target)
-
97
candidates.find_all { |c| c.attributes.slice(*attributes.keys) == attributes }
-
end
-
-
1
def delete_through_records(records)
-
39
records.each do |record|
-
46
through_records = through_records_for(record)
-
-
46
if through_reflection.macro == :has_many
-
63
through_records.each { |r| through_association.target.delete(r) }
-
else
-
1
if through_records.include?(through_association.target)
-
through_association.target = nil
-
end
-
end
-
-
46
@through_records.delete(record.object_id)
-
end
-
end
-
-
1
def find_target
-
157
return [] unless target_reflection_has_associated_record?
-
156
scope.to_a
-
end
-
-
# NOTE - not sure that we can actually cope with inverses here
-
1
def invertible_for?(record)
-
358
false
-
end
-
end
-
end
-
end
-
-
1
module ActiveRecord
-
# = Active Record Belongs To Has One Association
-
1
module Associations
-
1
class HasOneAssociation < SingularAssociation #:nodoc:
-
-
1
def handle_dependency
-
27
case options[:dependent]
-
when :restrict, :restrict_with_exception
-
4
raise ActiveRecord::DeleteRestrictionError.new(reflection.name) if load_target
-
-
when :restrict_with_error
-
2
if load_target
-
1
record = klass.human_attribute_name(reflection.name).downcase
-
1
owner.errors.add(:base, :"restrict_dependent_destroy.one", record: record)
-
1
false
-
end
-
-
else
-
21
delete
-
end
-
end
-
-
1
def replace(record, save = true)
-
172
raise_on_type_mismatch(record) if record
-
170
load_target
-
-
# If target and record are nil, or target is equal to record,
-
# we don't need to have transaction.
-
170
if (target || record) && target != record
-
75
transaction_if(save) do
-
75
remove_target!(options[:dependent]) if target && !target.destroyed?
-
-
74
if record
-
71
set_owner_attributes(record)
-
71
set_inverse_instance(record)
-
-
71
if owner.persisted? && save && !record.save
-
2
nullify_owner_attributes(record)
-
2
set_owner_attributes(target) if target
-
2
raise RecordNotSaved, "Failed to save the new associated #{reflection.name}."
-
end
-
end
-
end
-
end
-
-
167
self.target = record
-
end
-
-
1
def delete(method = options[:dependent])
-
21
if load_target
-
11
case method
-
when :delete
-
4
target.delete
-
when :destroy
-
5
target.destroy
-
when :nullify
-
2
target.update_columns(reflection.foreign_key => nil)
-
end
-
end
-
end
-
-
1
private
-
-
# The reason that the save param for replace is false, if for create (not just build),
-
# is because the setting of the foreign keys is actually handled by the scoping when
-
# the record is instantiated, and so they are set straight away and do not need to be
-
# updated within replace.
-
1
def set_new_record(record)
-
133
replace(record, false)
-
end
-
-
1
def remove_target!(method)
-
34
case method
-
when :delete
-
1
target.delete
-
when :destroy
-
8
target.destroy
-
else
-
25
nullify_owner_attributes(target)
-
-
25
if target.persisted? && owner.persisted? && !target.save
-
1
set_owner_attributes(target)
-
1
raise RecordNotSaved, "Failed to remove the existing associated #{reflection.name}. " +
-
"The record failed to save after its foreign key was set to nil."
-
end
-
end
-
end
-
-
1
def nullify_owner_attributes(record)
-
27
record[reflection.foreign_key] = nil
-
end
-
-
1
def transaction_if(value)
-
75
if value
-
60
reflection.klass.transaction { yield }
-
else
-
45
yield
-
end
-
end
-
end
-
end
-
end
-
1
module ActiveRecord
-
# = Active Record Has One Through Association
-
1
module Associations
-
1
class HasOneThroughAssociation < HasOneAssociation #:nodoc:
-
1
include ThroughAssociation
-
-
1
def replace(record)
-
12
create_through_record(record)
-
11
self.target = record
-
end
-
-
1
private
-
-
1
def create_through_record(record)
-
12
ensure_not_nested
-
-
11
through_proxy = owner.association(through_reflection.name)
-
11
through_record = through_proxy.send(:load_target)
-
-
11
if through_record && !record
-
1
through_record.destroy
-
10
elsif record
-
10
attributes = construct_join_attributes(record)
-
-
10
if through_record
-
6
through_record.update_attributes(attributes)
-
4
elsif owner.new_record?
-
2
through_proxy.build(attributes)
-
else
-
2
through_proxy.create(attributes)
-
end
-
end
-
end
-
end
-
end
-
end
-
1
module ActiveRecord
-
1
module Associations
-
1
class JoinDependency # :nodoc:
-
1
autoload :JoinPart, 'active_record/associations/join_dependency/join_part'
-
1
autoload :JoinBase, 'active_record/associations/join_dependency/join_base'
-
1
autoload :JoinAssociation, 'active_record/associations/join_dependency/join_association'
-
-
1
attr_reader :join_parts, :reflections, :alias_tracker, :active_record
-
-
1
def initialize(base, associations, joins)
-
1454
@active_record = base
-
1454
@table_joins = joins
-
1454
@join_parts = [JoinBase.new(base)]
-
1454
@associations = {}
-
1454
@reflections = []
-
1454
@alias_tracker = AliasTracker.new(base.connection, joins)
-
1454
@alias_tracker.aliased_name_for(base.table_name) # Updates the count for base.table_name to 1
-
1454
build(associations)
-
end
-
-
1
def graft(*associations)
-
1096
associations.each do |association|
-
114
join_associations.detect {|a| association == a} ||
-
241
build(association.reflection.name, association.find_parent_in(self) || join_base, association.join_type)
-
end
-
1096
self
-
end
-
-
1
def join_associations
-
2654
join_parts.last(join_parts.length - 1)
-
end
-
-
1
def join_base
-
973
join_parts.first
-
end
-
-
1
def columns
-
334
join_parts.collect { |join_part|
-
476
table = join_part.aliased_table
-
476
join_part.column_names_with_alias.collect{ |column_name, aliased_name|
-
4266
table[column_name].as Arel.sql(aliased_name)
-
}
-
}.flatten
-
end
-
-
1
def instantiate(rows)
-
92
primary_key = join_base.aliased_primary_key
-
92
parents = {}
-
-
92
records = rows.map { |model|
-
392
primary_id = model[primary_key]
-
392
parent = parents[primary_id] ||= join_base.instantiate(model)
-
392
construct(parent, @associations, join_associations, model)
-
392
parent
-
}.uniq
-
-
92
remove_duplicate_results!(active_record, records, @associations)
-
92
records
-
end
-
-
1
def remove_duplicate_results!(base, records, associations)
-
207
case associations
-
when Symbol, String
-
reflection = base.reflections[associations]
-
remove_uniq_by_reflection(reflection, records)
-
when Array
-
associations.each do |association|
-
remove_duplicate_results!(base, records, association)
-
end
-
when Hash
-
207
associations.keys.each do |name|
-
130
reflection = base.reflections[name]
-
130
remove_uniq_by_reflection(reflection, records)
-
-
130
parent_records = []
-
130
records.each do |record|
-
289
if descendant = record.send(reflection.name)
-
258
if reflection.collection?
-
136
parent_records.concat descendant.target.uniq
-
else
-
122
parent_records << descendant
-
end
-
end
-
end
-
-
130
remove_duplicate_results!(reflection.klass, parent_records, associations[name]) unless parent_records.empty?
-
end
-
end
-
end
-
-
1
protected
-
-
1
def cache_joined_association(association)
-
559
associations = []
-
559
parent = association.parent
-
559
while parent != join_base
-
110
associations.unshift(parent.reflection.name)
-
110
parent = parent.parent
-
end
-
559
ref = @associations
-
559
associations.each do |key|
-
110
ref = ref[key]
-
end
-
559
ref[association.reflection.name] ||= {}
-
end
-
-
1
def build(associations, parent = nil, join_type = Arel::InnerJoin)
-
2061
parent ||= join_parts.last
-
2061
case associations
-
when Symbol, String
-
reflection = parent.reflections[associations.to_s.intern] or
-
568
raise ConfigurationError, "Association named '#{ associations }' was not found; perhaps you misspelled it?"
-
568
unless join_association = find_join_association(reflection, parent)
-
560
@reflections << reflection
-
560
join_association = build_join_association(reflection, parent)
-
559
join_association.join_type = join_type
-
559
@join_parts << join_association
-
559
cache_joined_association(join_association)
-
end
-
567
join_association
-
when Array
-
1457
associations.each do |association|
-
291
build(association, parent, join_type)
-
end
-
when Hash
-
74
associations.keys.sort_by { |a| a.to_s }.each do |name|
-
38
join_association = build(name, parent, join_type)
-
38
build(associations[name], join_association, join_type)
-
end
-
else
-
raise ConfigurationError, associations.inspect
-
end
-
end
-
-
1
def find_join_association(name_or_reflection, parent)
-
568
if String === name_or_reflection
-
name_or_reflection = name_or_reflection.to_sym
-
end
-
-
568
join_associations.detect { |j|
-
216
j.reflection == name_or_reflection && j.parent == parent
-
}
-
end
-
-
1
def remove_uniq_by_reflection(reflection, records)
-
130
if reflection && reflection.collection?
-
211
records.each { |record| record.send(reflection.name).target.uniq! }
-
end
-
end
-
-
1
def build_join_association(reflection, parent)
-
560
JoinAssociation.new(reflection, self, parent)
-
end
-
-
1
def construct(parent, associations, join_parts, row)
-
1454
case associations
-
when Symbol, String
-
561
name = associations.to_s
-
-
561
join_part = join_parts.detect { |j|
-
j.reflection.name.to_s == name &&
-
572
j.parent_table_name == parent.class.table_name }
-
-
561
raise(ConfigurationError, "No such association") unless join_part
-
-
561
join_parts.delete(join_part)
-
561
construct_association(parent, join_part, row)
-
when Array
-
associations.each do |association|
-
construct(parent, association, join_parts, row)
-
end
-
when Hash
-
1454
associations.sort_by { |k,_| k.to_s }.each do |association_name, assoc|
-
561
association = construct(parent, association_name, join_parts, row)
-
561
construct(association, assoc, join_parts, row) if association
-
end
-
else
-
raise ConfigurationError, associations.inspect
-
end
-
end
-
-
1
def construct_association(record, join_part, row)
-
561
return if record.id.to_s != join_part.parent.record_id(row).to_s
-
-
560
macro = join_part.reflection.macro
-
560
if macro == :has_one
-
119
return record.association(join_part.reflection.name).target if record.association_cache.key?(join_part.reflection.name)
-
60
association = join_part.instantiate(row) unless row[join_part.aliased_primary_key].nil?
-
60
set_target_and_inverse(join_part, association, record)
-
else
-
441
association = join_part.instantiate(row) unless row[join_part.aliased_primary_key].nil?
-
441
case macro
-
when :has_many, :has_and_belongs_to_many
-
322
other = record.association(join_part.reflection.name)
-
322
other.loaded!
-
322
other.target.push(association) if association
-
322
other.set_inverse_instance(association)
-
when :belongs_to
-
119
set_target_and_inverse(join_part, association, record)
-
else
-
raise ConfigurationError, "unknown macro: #{join_part.reflection.macro}"
-
end
-
end
-
501
association
-
end
-
-
1
def set_target_and_inverse(join_part, association, record)
-
179
other = record.association(join_part.reflection.name)
-
179
other.target = association
-
179
other.set_inverse_instance(association)
-
end
-
end
-
end
-
end
-
1
module ActiveRecord
-
1
module Associations
-
1
class JoinDependency # :nodoc:
-
1
class JoinAssociation < JoinPart # :nodoc:
-
1
include JoinHelper
-
-
# The reflection of the association represented
-
1
attr_reader :reflection
-
-
# The JoinDependency object which this JoinAssociation exists within. This is mainly
-
# relevant for generating aliases which do not conflict with other joins which are
-
# part of the query.
-
1
attr_reader :join_dependency
-
-
# A JoinBase instance representing the active record we are joining onto.
-
# (So in Author.has_many :posts, the Author would be that base record.)
-
1
attr_reader :parent
-
-
# What type of join will be generated, either Arel::InnerJoin (default) or Arel::OuterJoin
-
1
attr_accessor :join_type
-
-
# These implement abstract methods from the superclass
-
1
attr_reader :aliased_prefix
-
-
1
attr_reader :tables
-
-
1
delegate :options, :through_reflection, :source_reflection, :chain, :to => :reflection
-
1
delegate :table, :table_name, :to => :parent, :prefix => :parent
-
1
delegate :alias_tracker, :to => :join_dependency
-
-
1
alias :alias_suffix :parent_table_name
-
-
1
def initialize(reflection, join_dependency, parent = nil)
-
560
reflection.check_validity!
-
-
560
if reflection.options[:polymorphic]
-
1
raise EagerLoadPolymorphicError.new(reflection)
-
end
-
-
559
super(reflection.klass)
-
-
559
@reflection = reflection
-
559
@join_dependency = join_dependency
-
559
@parent = parent
-
559
@join_type = Arel::InnerJoin
-
559
@aliased_prefix = "t#{ join_dependency.join_parts.size }"
-
559
@tables = construct_tables.reverse
-
end
-
-
1
def ==(other)
-
other.class == self.class &&
-
692
other.reflection == reflection &&
-
other.parent == parent
-
end
-
-
1
def find_parent_in(other_join_dependency)
-
240
other_join_dependency.join_parts.detect do |join_part|
-
305
parent == join_part
-
end
-
end
-
-
1
def join_to(relation)
-
387
tables = @tables.dup
-
387
foreign_table = parent_table
-
387
foreign_klass = parent.active_record
-
-
# The chain starts with the target table, but we want to end with it here (makes
-
# more sense in this context), so we reverse
-
387
chain.reverse.each_with_index do |reflection, i|
-
530
table = tables.shift
-
-
530
case reflection.source_macro
-
when :belongs_to
-
172
key = reflection.association_primary_key
-
172
foreign_key = reflection.foreign_key
-
when :has_and_belongs_to_many
-
# Join the join table first...
-
18
relation.from(join(
-
table,
-
table[reflection.foreign_key].
-
eq(foreign_table[reflection.active_record_primary_key])
-
))
-
-
18
foreign_table, table = table, tables.shift
-
-
18
key = reflection.association_primary_key
-
18
foreign_key = reflection.association_foreign_key
-
else
-
340
key = reflection.foreign_key
-
340
foreign_key = reflection.active_record_primary_key
-
end
-
-
530
constraint = build_constraint(reflection, table, key, foreign_table, foreign_key)
-
-
530
scope_chain_items = scope_chain[i]
-
-
530
if reflection.type
-
43
scope_chain_items += [
-
ActiveRecord::Relation.new(reflection.klass, table)
-
.where(reflection.type => foreign_klass.base_class.name)
-
]
-
end
-
-
530
scope_chain_items.each do |item|
-
197
unless item.is_a?(Relation)
-
149
item = ActiveRecord::Relation.new(reflection.klass, table).instance_exec(self, &item)
-
end
-
-
197
constraint = constraint.and(item.arel.constraints) unless item.arel.constraints.empty?
-
end
-
-
530
relation.from(join(table, constraint))
-
-
# The current table in this iteration becomes the foreign table in the next
-
530
foreign_table, foreign_klass = table, reflection.klass
-
end
-
-
387
relation
-
end
-
-
1
def build_constraint(reflection, table, key, foreign_table, foreign_key)
-
530
constraint = table[key].eq(foreign_table[foreign_key])
-
-
530
if reflection.klass.finder_needs_type_condition?
-
39
constraint = table.create_and([
-
constraint,
-
reflection.klass.send(:type_condition, table)
-
])
-
end
-
-
530
constraint
-
end
-
-
1
def join_relation(joining_relation)
-
172
self.join_type = Arel::OuterJoin
-
172
joining_relation.joins(self)
-
end
-
-
1
def table
-
457
tables.last
-
end
-
-
1
def aliased_table_name
-
143
table.table_alias || table.name
-
end
-
-
1
def scope_chain
-
530
@scope_chain ||= reflection.scope_chain.reverse
-
end
-
-
end
-
end
-
end
-
end
-
1
module ActiveRecord
-
1
module Associations
-
1
class JoinDependency # :nodoc:
-
1
class JoinBase < JoinPart # :nodoc:
-
1
def ==(other)
-
other.class == self.class &&
-
821
other.active_record == active_record
-
end
-
-
1
def aliased_prefix
-
4045
"t0"
-
end
-
-
1
def table
-
669
Arel::Table.new(table_name, arel_engine)
-
end
-
-
1
def aliased_table_name
-
334
active_record.table_name
-
end
-
end
-
end
-
end
-
end
-
1
module ActiveRecord
-
1
module Associations
-
1
class JoinDependency # :nodoc:
-
# A JoinPart represents a part of a JoinDependency. It is an abstract class, inherited
-
# by JoinBase and JoinAssociation. A JoinBase represents the Active Record which
-
# everything else is being joined onto. A JoinAssociation represents an association which
-
# is joining to the base. A JoinAssociation may result in more than one actual join
-
# operations (for example a has_and_belongs_to_many JoinAssociation would result in
-
# two; one for the join table and one for the target table).
-
1
class JoinPart # :nodoc:
-
# The Active Record class which this join part is associated 'about'; for a JoinBase
-
# this is the actual base model, for a JoinAssociation this is the target model of the
-
# association.
-
1
attr_reader :active_record
-
-
1
delegate :table_name, :column_names, :primary_key, :reflections, :arel_engine, :to => :active_record
-
-
1
def initialize(active_record)
-
2014
@active_record = active_record
-
2014
@cached_record = {}
-
2014
@column_names_with_alias = nil
-
end
-
-
1
def aliased_table
-
476
Arel::Nodes::TableAlias.new table, aliased_table_name
-
end
-
-
1
def ==(other)
-
raise NotImplementedError
-
end
-
-
# An Arel::Table for the active_record
-
1
def table
-
raise NotImplementedError
-
end
-
-
# The prefix to be used when aliasing columns in the active_record's table
-
1
def aliased_prefix
-
raise NotImplementedError
-
end
-
-
# The alias for the active_record's table
-
1
def aliased_table_name
-
raise NotImplementedError
-
end
-
-
# The alias for the primary key of the active_record's table
-
1
def aliased_primary_key
-
1808
"#{aliased_prefix}_r0"
-
end
-
-
# An array of [column_name, alias] pairs for the table
-
1
def column_names_with_alias
-
979
unless @column_names_with_alias
-
477
@column_names_with_alias = []
-
-
477
([primary_key] + (column_names - [primary_key])).compact.each_with_index do |column_name, i|
-
4268
@column_names_with_alias << [column_name, "#{aliased_prefix}_r#{i}"]
-
end
-
end
-
979
@column_names_with_alias
-
end
-
-
1
def extract_record(row)
-
4486
Hash[column_names_with_alias.map{|cn, an| [cn, row[an]]}]
-
end
-
-
1
def record_id(row)
-
1215
row[aliased_primary_key]
-
end
-
-
1
def instantiate(row)
-
654
@cached_record[record_id(row)] ||= active_record.send(:instantiate, extract_record(row))
-
end
-
end
-
end
-
end
-
end
-
1
module ActiveRecord
-
1
module Associations
-
# Helper class module which gets mixed into JoinDependency::JoinAssociation and AssociationScope
-
1
module JoinHelper #:nodoc:
-
-
1
def join_type
-
987
Arel::InnerJoin
-
end
-
-
1
private
-
-
1
def construct_tables
-
3437
tables = []
-
3437
chain.each do |reflection|
-
tables << alias_tracker.aliased_table_for(
-
table_name_for(reflection),
-
table_alias_for(reflection, reflection != self.reflection)
-
4137
)
-
-
4137
if reflection.source_macro == :has_and_belongs_to_many
-
tables << alias_tracker.aliased_table_for(
-
498
(reflection.source_reflection || reflection).join_table,
-
table_alias_for(reflection, true)
-
498
)
-
end
-
end
-
3437
tables
-
end
-
-
1
def table_name_for(reflection)
-
741
reflection.table_name
-
end
-
-
1
def table_alias_for(reflection, join = false)
-
4635
name = "#{reflection.plural_name}_#{alias_suffix}"
-
4635
name << "_join" if join
-
4635
name
-
end
-
-
1
def join(table, constraint)
-
1535
table.create_join(table, table.create_on(constraint), join_type)
-
end
-
end
-
end
-
end
-
1
module ActiveRecord
-
1
module Associations
-
# Implements the details of eager loading of Active Record associations.
-
#
-
# Note that 'eager loading' and 'preloading' are actually the same thing.
-
# However, there are two different eager loading strategies.
-
#
-
# The first one is by using table joins. This was only strategy available
-
# prior to Rails 2.1. Suppose that you have an Author model with columns
-
# 'name' and 'age', and a Book model with columns 'name' and 'sales'. Using
-
# this strategy, Active Record would try to retrieve all data for an author
-
# and all of its books via a single query:
-
#
-
# SELECT * FROM authors
-
# LEFT OUTER JOIN books ON authors.id = books.author_id
-
# WHERE authors.name = 'Ken Akamatsu'
-
#
-
# However, this could result in many rows that contain redundant data. After
-
# having received the first row, we already have enough data to instantiate
-
# the Author object. In all subsequent rows, only the data for the joined
-
# 'books' table is useful; the joined 'authors' data is just redundant, and
-
# processing this redundant data takes memory and CPU time. The problem
-
# quickly becomes worse and worse as the level of eager loading increases
-
# (i.e. if Active Record is to eager load the associations' associations as
-
# well).
-
#
-
# The second strategy is to use multiple database queries, one for each
-
# level of association. Since Rails 2.1, this is the default strategy. In
-
# situations where a table join is necessary (e.g. when the +:conditions+
-
# option references an association's column), it will fallback to the table
-
# join strategy.
-
1
class Preloader #:nodoc:
-
1
extend ActiveSupport::Autoload
-
-
1
eager_autoload do
-
1
autoload :Association, 'active_record/associations/preloader/association'
-
1
autoload :SingularAssociation, 'active_record/associations/preloader/singular_association'
-
1
autoload :CollectionAssociation, 'active_record/associations/preloader/collection_association'
-
1
autoload :ThroughAssociation, 'active_record/associations/preloader/through_association'
-
-
1
autoload :HasMany, 'active_record/associations/preloader/has_many'
-
1
autoload :HasManyThrough, 'active_record/associations/preloader/has_many_through'
-
1
autoload :HasOne, 'active_record/associations/preloader/has_one'
-
1
autoload :HasOneThrough, 'active_record/associations/preloader/has_one_through'
-
1
autoload :HasAndBelongsToMany, 'active_record/associations/preloader/has_and_belongs_to_many'
-
1
autoload :BelongsTo, 'active_record/associations/preloader/belongs_to'
-
end
-
-
1
attr_reader :records, :associations, :preload_scope, :model
-
-
# Eager loads the named associations for the given Active Record record(s).
-
#
-
# In this description, 'association name' shall refer to the name passed
-
# to an association creation method. For example, a model that specifies
-
# <tt>belongs_to :author</tt>, <tt>has_many :buyers</tt> has association
-
# names +:author+ and +:buyers+.
-
#
-
# == Parameters
-
# +records+ is an array of ActiveRecord::Base. This array needs not be flat,
-
# i.e. +records+ itself may also contain arrays of records. In any case,
-
# +preload_associations+ will preload the all associations records by
-
# flattening +records+.
-
#
-
# +associations+ specifies one or more associations that you want to
-
# preload. It may be:
-
# - a Symbol or a String which specifies a single association name. For
-
# example, specifying +:books+ allows this method to preload all books
-
# for an Author.
-
# - an Array which specifies multiple association names. This array
-
# is processed recursively. For example, specifying <tt>[:avatar, :books]</tt>
-
# allows this method to preload an author's avatar as well as all of his
-
# books.
-
# - a Hash which specifies multiple association names, as well as
-
# association names for the to-be-preloaded association objects. For
-
# example, specifying <tt>{ author: :avatar }</tt> will preload a
-
# book's author, as well as that author's avatar.
-
#
-
# +:associations+ has the same format as the +:include+ option for
-
# <tt>ActiveRecord::Base.find</tt>. So +associations+ could look like this:
-
#
-
# :books
-
# [ :books, :author ]
-
# { author: :avatar }
-
# [ :books, { author: :avatar } ]
-
1
def initialize(records, associations, preload_scope = nil)
-
552
@records = Array.wrap(records).compact.uniq
-
552
@associations = Array.wrap(associations)
-
552
@preload_scope = preload_scope || Relation.new(nil, nil)
-
end
-
-
1
def run
-
552
unless records.empty?
-
1034
associations.each { |association| preload(association) }
-
end
-
end
-
-
1
private
-
-
1
def preload(association)
-
518
case association
-
when Hash
-
32
preload_hash(association)
-
when String, Symbol
-
486
preload_one(association.to_sym)
-
else
-
raise ArgumentError, "#{association.inspect} was not recognised for preload"
-
end
-
end
-
-
1
def preload_hash(association)
-
32
association.each do |parent, child|
-
32
Preloader.new(records, parent, preload_scope).run
-
189
Preloader.new(records.map { |record| record.send(parent) }.flatten, child).run
-
end
-
end
-
-
# Not all records have the same class, so group then preload group on the reflection
-
# itself so that if various subclass share the same association then we do not split
-
# them unnecessarily
-
#
-
# Additionally, polymorphic belongs_to associations can have multiple associated
-
# classes, depending on the polymorphic_type field. So we group by the classes as
-
# well.
-
1
def preload_one(association)
-
486
grouped_records(association).each do |reflection, klasses|
-
484
klasses.each do |klass, records|
-
489
preloader_for(reflection).new(klass, records, reflection, preload_scope).run
-
end
-
end
-
end
-
-
1
def grouped_records(association)
-
486
Hash[
-
records_by_reflection(association).map do |reflection, records|
-
2174
[reflection, records.group_by { |record| association_klass(reflection, record) }]
-
end
-
]
-
end
-
-
1
def records_by_reflection(association)
-
486
records.group_by do |record|
-
1694
reflection = record.class.reflections[association]
-
-
1694
unless reflection
-
4
raise ActiveRecord::ConfigurationError, "Association named '#{association}' was not found; " \
-
"perhaps you misspelled it?"
-
end
-
-
1690
reflection
-
end
-
end
-
-
1
def association_klass(reflection, record)
-
1690
if reflection.macro == :belongs_to && reflection.options[:polymorphic]
-
221
klass = record.send(reflection.foreign_type)
-
221
klass && klass.constantize
-
else
-
1469
reflection.klass
-
end
-
end
-
-
1
def preloader_for(reflection)
-
489
case reflection.macro
-
when :has_many
-
186
reflection.options[:through] ? HasManyThrough : HasMany
-
when :has_one
-
116
reflection.options[:through] ? HasOneThrough : HasOne
-
when :has_and_belongs_to_many
-
57
HasAndBelongsToMany
-
when :belongs_to
-
130
BelongsTo
-
end
-
end
-
end
-
end
-
end
-
1
module ActiveRecord
-
1
module Associations
-
1
class Preloader
-
1
class Association #:nodoc:
-
1
attr_reader :owners, :reflection, :preload_scope, :model, :klass
-
-
1
def initialize(klass, owners, reflection, preload_scope)
-
489
@klass = klass
-
489
@owners = owners
-
489
@reflection = reflection
-
489
@preload_scope = preload_scope
-
489
@model = owners.first && owners.first.class
-
489
@scope = nil
-
489
@owners_by_key = nil
-
end
-
-
1
def run
-
489
unless owners.first.association(reflection.name).loaded?
-
480
preload
-
end
-
end
-
-
1
def preload
-
raise NotImplementedError
-
end
-
-
1
def scope
-
416
@scope ||= build_scope
-
end
-
-
1
def records_for(ids)
-
416
scope.where(association_key.in(ids))
-
end
-
-
1
def table
-
937
klass.arel_table
-
end
-
-
# The name of the key on the associated records
-
1
def association_key_name
-
raise NotImplementedError
-
end
-
-
# This is overridden by HABTM as the condition should be on the foreign_key column in
-
# the join table
-
1
def association_key
-
357
table[association_key_name]
-
end
-
-
# The name of the key on the model which declares the association
-
1
def owner_key_name
-
raise NotImplementedError
-
end
-
-
# We're converting to a string here because postgres will return the aliased association
-
# key in a habtm as a string (for whatever reason)
-
1
def owners_by_key
-
@owners_by_key ||= owners.group_by do |owner|
-
1511
key = owner[owner_key_name]
-
1511
key && key.to_s
-
416
end
-
end
-
-
1
def options
-
490
reflection.options
-
end
-
-
1
private
-
-
1
def associated_records_by_owner
-
416
owners_map = owners_by_key
-
416
owner_keys = owners_map.keys.compact
-
-
416
if klass.nil? || owner_keys.empty?
-
5
records = []
-
else
-
# Some databases impose a limit on the number of ids in a list (in Oracle it's 1000)
-
# Make several smaller queries if necessary or make one query if the adapter supports it
-
411
sliced = owner_keys.each_slice(model.connection.in_clause_length || owner_keys.size)
-
827
records = sliced.map { |slice| records_for(slice).to_a }.flatten
-
end
-
-
# Each record may have multiple owners, and vice-versa
-
1927
records_by_owner = Hash[owners.map { |owner| [owner, []] }]
-
416
records.each do |record|
-
1748
owner_key = record[association_key_name].to_s
-
-
1748
owners_map[owner_key].each do |owner|
-
1919
records_by_owner[owner] << record
-
end
-
end
-
416
records_by_owner
-
end
-
-
1
def reflection_scope
-
1055
@reflection_scope ||= reflection.scope ? klass.unscoped.instance_exec(nil, &reflection.scope) : klass.unscoped
-
end
-
-
1
def build_scope
-
411
scope = klass.unscoped
-
411
scope.default_scoped = true
-
-
411
values = reflection_scope.values
-
411
preload_values = preload_scope.values
-
-
411
scope.where_values = Array(values[:where]) + Array(preload_values[:where])
-
411
scope.references_values = Array(values[:references]) + Array(preload_values[:references])
-
-
411
scope.select! preload_values[:select] || values[:select] || table[Arel.star]
-
411
scope.includes! preload_values[:includes] || values[:includes]
-
-
411
if options[:as]
-
24
scope.where!(klass.table_name => { reflection.type => model.base_class.sti_name })
-
end
-
-
411
scope
-
end
-
end
-
end
-
end
-
end
-
1
module ActiveRecord
-
1
module Associations
-
1
class Preloader
-
1
class BelongsTo < SingularAssociation #:nodoc:
-
-
1
def association_key_name
-
485
reflection.options[:primary_key] || klass && klass.primary_key
-
end
-
-
1
def owner_key_name
-
554
reflection.foreign_key
-
end
-
-
end
-
end
-
end
-
end
-
1
module ActiveRecord
-
1
module Associations
-
1
class Preloader
-
1
class CollectionAssociation < Association #:nodoc:
-
-
1
private
-
-
1
def build_scope
-
193
super.order(preload_scope.values[:order] || reflection_scope.values[:order])
-
end
-
-
1
def preload
-
240
associated_records_by_owner.each do |owner, records|
-
906
association = owner.association(reflection.name)
-
906
association.loaded!
-
906
association.target.concat(records)
-
2124
records.each { |record| association.set_inverse_instance(record) }
-
end
-
end
-
-
end
-
end
-
end
-
end
-
1
module ActiveRecord
-
1
module Associations
-
1
class Preloader
-
1
class HasAndBelongsToMany < CollectionAssociation #:nodoc:
-
1
attr_reader :join_table
-
-
1
def initialize(klass, records, reflection, preload_options)
-
57
super
-
57
@join_table = Arel::Table.new(reflection.join_table).alias('t0')
-
end
-
-
# Unlike the other associations, we want to get a raw array of rows so that we can
-
# access the aliased column on the join table
-
1
def records_for(ids)
-
59
scope = super
-
59
klass.connection.select_all(scope.arel, 'SQL', scope.bind_values)
-
end
-
-
1
def owner_key_name
-
333
reflection.active_record_primary_key
-
end
-
-
1
def association_key_name
-
421
'ar_association_key_name'
-
end
-
-
1
def association_key
-
116
join_table[reflection.foreign_key]
-
end
-
-
1
private
-
-
# Once we have used the join table column (in super), we manually instantiate the
-
# actual records, ensuring that we don't create more than one instances of the same
-
# record
-
1
def associated_records_by_owner
-
57
records = {}
-
57
super.each do |owner_key, rows|
-
697
rows.map! { |row| records[row[klass.primary_key]] ||= klass.instantiate(row) }
-
end
-
end
-
-
1
def build_scope
-
57
super.joins(join).select(join_select)
-
end
-
-
1
def join_select
-
57
association_key.as(Arel.sql(association_key_name))
-
end
-
-
1
def join
-
57
condition = table[reflection.association_primary_key].eq(
-
join_table[reflection.association_foreign_key])
-
-
57
table.create_join(join_table, table.create_on(condition))
-
end
-
end
-
end
-
end
-
end
-
1
module ActiveRecord
-
1
module Associations
-
1
class Preloader
-
1
class HasMany < CollectionAssociation #:nodoc:
-
-
1
def association_key_name
-
806
reflection.foreign_key
-
end
-
-
1
def owner_key_name
-
438
reflection.active_record_primary_key
-
end
-
-
end
-
end
-
end
-
end
-
1
module ActiveRecord
-
1
module Associations
-
1
class Preloader
-
1
class HasManyThrough < CollectionAssociation #:nodoc:
-
1
include ThroughAssociation
-
-
1
def associated_records_by_owner
-
46
super.each do |owner, records|
-
135
records.uniq! if reflection_scope.uniq_value
-
end
-
end
-
end
-
end
-
end
-
end
-
1
module ActiveRecord
-
1
module Associations
-
1
class Preloader
-
1
class HasOne < SingularAssociation #:nodoc:
-
-
1
def association_key_name
-
450
reflection.foreign_key
-
end
-
-
1
def owner_key_name
-
186
reflection.active_record_primary_key
-
end
-
-
1
private
-
-
1
def build_scope
-
97
super.order(preload_scope.values[:order] || reflection_scope.values[:order])
-
end
-
-
end
-
end
-
end
-
end
-
1
module ActiveRecord
-
1
module Associations
-
1
class Preloader
-
1
class HasOneThrough < SingularAssociation #:nodoc:
-
1
include ThroughAssociation
-
end
-
end
-
end
-
end
-
1
module ActiveRecord
-
1
module Associations
-
1
class Preloader
-
1
class SingularAssociation < Association #:nodoc:
-
-
1
private
-
-
1
def preload
-
240
associated_records_by_owner.each do |owner, associated_records|
-
770
record = associated_records.first
-
-
770
association = owner.association(reflection.name)
-
770
association.target = record
-
770
association.set_inverse_instance(record)
-
end
-
end
-
-
end
-
end
-
end
-
end
-
1
module ActiveRecord
-
1
module Associations
-
1
class Preloader
-
1
module ThroughAssociation #:nodoc:
-
-
1
def through_reflection
-
298
reflection.through_reflection
-
end
-
-
1
def source_reflection
-
251
reflection.source_reflection
-
end
-
-
1
def associated_records_by_owner
-
64
through_records = through_records_by_owner
-
-
64
Preloader.new(through_records.values.flatten, source_reflection.name, reflection_scope).run
-
-
64
through_records.each do |owner, records|
-
352
records.map! { |r| r.send(source_reflection.name) }.flatten!
-
165
records.compact!
-
end
-
end
-
-
1
private
-
-
1
def through_records_by_owner
-
64
Preloader.new(owners, through_reflection.name, through_scope).run
-
-
64
Hash[owners.map do |owner|
-
165
through_records = Array.wrap(owner.send(through_reflection.name))
-
-
# Dont cache the association - we would only be caching a subset
-
165
if reflection.options[:source_type] && through_reflection.collection?
-
1
owner.association(through_reflection.name).reset
-
end
-
-
165
[owner, through_records]
-
end]
-
end
-
-
1
def through_scope
-
64
through_scope = through_reflection.klass.unscoped
-
-
64
if options[:source_type]
-
4
through_scope.where! reflection.foreign_type => options[:source_type]
-
else
-
60
unless reflection_scope.where_values.empty?
-
11
through_scope.includes_values = reflection_scope.values[:includes] || options[:source]
-
11
through_scope.where_values = reflection_scope.values[:where]
-
end
-
-
60
through_scope.order! reflection_scope.values[:order]
-
60
through_scope.references! reflection_scope.values[:references]
-
end
-
-
64
through_scope
-
end
-
end
-
end
-
end
-
end
-
1
module ActiveRecord
-
1
module Associations
-
1
class SingularAssociation < Association #:nodoc:
-
# Implements the reader method, e.g. foo.bar for Foo.has_one :bar
-
1
def reader(force_reload = false)
-
2094
if force_reload
-
26
klass.uncached { reload }
-
elsif !loaded? || stale_target?
-
487
reload
-
end
-
-
2094
target
-
end
-
-
# Implements the writer method, e.g. foo.bar= for Foo.belongs_to :bar
-
1
def writer(record)
-
235
replace(record)
-
end
-
-
1
def create(attributes = {}, &block)
-
124
create_record(attributes, &block)
-
end
-
-
1
def create!(attributes = {}, &block)
-
10
create_record(attributes, true, &block)
-
end
-
-
1
def build(attributes = {})
-
69
record = build_record(attributes)
-
69
yield(record) if block_given?
-
69
set_new_record(record)
-
69
record
-
end
-
-
1
private
-
-
1
def create_scope
-
203
scope.scope_for_create.stringify_keys.except(klass.primary_key)
-
end
-
-
1
def find_target
-
1128
scope.first.tap { |record| set_inverse_instance(record) }
-
end
-
-
# Implemented by subclasses
-
1
def replace(record)
-
raise NotImplementedError, "Subclasses must implement a replace(record) method"
-
end
-
-
1
def set_new_record(record)
-
70
replace(record)
-
end
-
-
1
def create_record(attributes, raise_error = false)
-
134
record = build_record(attributes)
-
134
yield(record) if block_given?
-
134
saved = record.save
-
134
set_new_record(record)
-
134
raise RecordInvalid.new(record) if !saved && raise_error
-
132
record
-
end
-
end
-
end
-
end
-
1
module ActiveRecord
-
# = Active Record Through Association
-
1
module Associations
-
1
module ThroughAssociation #:nodoc:
-
-
1
delegate :source_reflection, :through_reflection, :chain, :to => :reflection
-
-
1
protected
-
-
# We merge in these scopes for two reasons:
-
#
-
# 1. To get the default_scope conditions for any of the other reflections in the chain
-
# 2. To get the type conditions for any STI models in the chain
-
1
def target_scope
-
930
scope = super
-
930
chain[1..-1].each do |reflection|
-
1039
scope = scope.merge(
-
reflection.klass.all.with_default_scope.
-
except(:select, :create_with, :includes, :preload, :joins, :eager_load)
-
)
-
end
-
930
scope
-
end
-
-
1
private
-
-
# Construct attributes for :through pointing to owner and associate. This is used by the
-
# methods which create and delete records on the association.
-
#
-
# We only support indirectly modifying through associations which has a belongs_to source.
-
# This is the "has_many :tags, through: :taggings" situation, where the join model
-
# typically has a belongs_to on both side. In other words, associations which could also
-
# be represented as has_and_belongs_to_many associations.
-
#
-
# We do not support creating/deleting records on the association where the source has
-
# some other type, because this opens up a whole can of worms, and in basically any
-
# situation it is more natural for the user to just create or modify their join records
-
# directly as required.
-
1
def construct_join_attributes(*records)
-
100
ensure_mutable
-
-
95
join_attributes = {
-
source_reflection.foreign_key =>
-
records.map { |record|
-
102
record.send(source_reflection.association_primary_key(reflection.klass))
-
}
-
}
-
-
95
if options[:source_type]
-
join_attributes[source_reflection.foreign_type] =
-
records.map { |record| record.class.base_class.name }
-
end
-
-
95
if records.count == 1
-
156
Hash[join_attributes.map { |k, v| [k, v.first] }]
-
else
-
17
join_attributes
-
end
-
end
-
-
# Note: this does not capture all cases, for example it would be crazy to try to
-
# properly support stale-checking for nested associations.
-
1
def stale_state
-
898
if through_reflection.macro == :belongs_to
-
60
owner[through_reflection.foreign_key] && owner[through_reflection.foreign_key].to_s
-
end
-
end
-
-
1
def foreign_key_present?
-
through_reflection.macro == :belongs_to &&
-
15
!owner[through_reflection.foreign_key].nil?
-
end
-
-
1
def ensure_mutable
-
174
if source_reflection.macro != :belongs_to
-
7
raise HasManyThroughCantAssociateThroughHasOneOrManyReflection.new(owner, reflection)
-
end
-
end
-
-
1
def ensure_not_nested
-
199
if reflection.nested?
-
8
raise HasManyThroughNestedAssociationsAreReadonly.new(owner, reflection)
-
end
-
end
-
end
-
end
-
end
-
-
1
module ActiveRecord
-
1
module AttributeAssignment
-
1
extend ActiveSupport::Concern
-
1
include ActiveModel::DeprecatedMassAssignmentSecurity
-
1
include ActiveModel::ForbiddenAttributesProtection
-
-
# Allows you to set all the attributes by passing in a hash of attributes with
-
# keys matching the attribute names (which again matches the column names).
-
#
-
# If the passed hash responds to <tt>permitted?</tt> method and the return value
-
# of this method is +false+ an <tt>ActiveModel::ForbiddenAttributesError</tt>
-
# exception is raised.
-
1
def assign_attributes(new_attributes)
-
3353
return if new_attributes.blank?
-
-
2833
attributes = new_attributes.stringify_keys
-
2833
multi_parameter_attributes = []
-
2833
nested_parameter_attributes = []
-
-
2833
attributes = sanitize_for_mass_assignment(attributes)
-
-
2832
attributes.each do |k, v|
-
3981
if k.include?("(")
-
160
multi_parameter_attributes << [ k, v ]
-
elsif v.is_a?(Hash)
-
134
nested_parameter_attributes << [ k, v ]
-
else
-
3687
_assign_attribute(k, v)
-
end
-
end
-
-
2828
assign_nested_parameter_attributes(nested_parameter_attributes) unless nested_parameter_attributes.empty?
-
2824
assign_multiparameter_attributes(multi_parameter_attributes) unless multi_parameter_attributes.empty?
-
end
-
-
1
alias attributes= assign_attributes
-
-
1
private
-
-
1
def _assign_attribute(k, v)
-
3821
public_send("#{k}=", v)
-
rescue NoMethodError
-
2
if respond_to?("#{k}=")
-
raise
-
else
-
2
raise UnknownAttributeError, "unknown attribute: #{k}"
-
end
-
end
-
-
# Assign any deferred nested attributes after the base attributes have been set.
-
1
def assign_nested_parameter_attributes(pairs)
-
268
pairs.each { |k, v| _assign_attribute(k, v) }
-
end
-
-
# Instantiates objects for all attribute classes that needs more than one constructor parameter. This is done
-
# by calling new on the column type or aggregation type (through composed_of) object with these parameters.
-
# So having the pairs written_on(1) = "2004", written_on(2) = "6", written_on(3) = "24", will instantiate
-
# written_on (a date type) with Date.new("2004", "6", "24"). You can also specify a typecast character in the
-
# parentheses to have the parameters typecasted before they're used in the constructor. Use i for Fixnum and
-
# f for Float. If all the values for a given attribute are empty, the attribute will be set to +nil+.
-
1
def assign_multiparameter_attributes(pairs)
-
execute_callstack_for_multiparameter_attributes(
-
41
extract_callstack_for_multiparameter_attributes(pairs)
-
)
-
end
-
-
1
def execute_callstack_for_multiparameter_attributes(callstack)
-
41
errors = []
-
41
callstack.each do |name, values_with_empty_parameters|
-
41
begin
-
41
send("#{name}=", MultiparameterAttribute.new(self, name, values_with_empty_parameters).read_value)
-
rescue => ex
-
7
errors << AttributeAssignmentError.new("error on assignment #{values_with_empty_parameters.values.inspect} to #{name} (#{ex.message})", ex, name)
-
end
-
end
-
41
unless errors.empty?
-
14
error_descriptions = errors.map { |ex| ex.message }.join(",")
-
7
raise MultiparameterAssignmentErrors.new(errors), "#{errors.size} error(s) on assignment of multiparameter attributes [#{error_descriptions}]"
-
end
-
end
-
-
1
def extract_callstack_for_multiparameter_attributes(pairs)
-
41
attributes = { }
-
-
41
pairs.each do |(multiparameter_name, value)|
-
160
attribute_name = multiparameter_name.split("(").first
-
160
attributes[attribute_name] ||= {}
-
-
160
parameter_value = value.empty? ? nil : type_cast_attribute_value(multiparameter_name, value)
-
160
attributes[attribute_name][find_parameter_position(multiparameter_name)] ||= parameter_value
-
end
-
-
41
attributes
-
end
-
-
1
def type_cast_attribute_value(multiparameter_name, value)
-
136
multiparameter_name =~ /\([0-9]*([if])\)/ ? value.send("to_" + $1) : value
-
end
-
-
1
def find_parameter_position(multiparameter_name)
-
160
multiparameter_name.scan(/\(([0-9]*).*\)/).first.first.to_i
-
end
-
-
1
class MultiparameterAttribute #:nodoc:
-
1
attr_reader :object, :name, :values, :column
-
-
1
def initialize(object, name, values)
-
41
@object = object
-
41
@name = name
-
41
@values = values
-
end
-
-
1
def read_value
-
41
return if values.values.compact.empty?
-
-
40
@column = object.class.reflect_on_aggregation(name.to_sym) || object.column_for_attribute(name)
-
40
klass = column.klass
-
-
40
if klass == Time
-
21
read_time
-
19
elsif klass == Date
-
14
read_date
-
else
-
5
read_other(klass)
-
end
-
end
-
-
1
private
-
-
1
def instantiate_time_object(set_values)
-
18
if object.class.send(:create_time_zone_conversion_attribute?, name, column)
-
1
Time.zone.local(*set_values)
-
else
-
17
Time.time_with_datetime_fallback(object.class.default_timezone, *set_values)
-
end
-
end
-
-
1
def read_time
-
# If column is a :time (and not :date or :timestamp) there is no need to validate if
-
# there are year/month/day fields
-
21
if column.type == :time
-
# if the column is a time set the values to their defaults as January 1, 1970, but only if they're nil
-
3
{ 1 => 1970, 2 => 1, 3 => 1 }.each do |key,value|
-
9
values[key] ||= value
-
end
-
else
-
# else column is a timestamp, so if Date bits were not provided, error
-
18
validate_missing_parameters!([1,2,3])
-
-
# If Date bits were provided but blank, then return nil
-
14
return if blank_date_parameter?
-
end
-
-
14
max_position = extract_max_param(6)
-
14
set_values = values.values_at(*(1..max_position))
-
# If Time bits are not there, then default to 0
-
56
(3..5).each { |i| set_values[i] = set_values[i].presence || 0 }
-
14
instantiate_time_object(set_values)
-
end
-
-
1
def read_date
-
14
return if blank_date_parameter?
-
8
set_values = values.values_at(1,2,3)
-
8
begin
-
8
Date.new(*set_values)
-
4
rescue ArgumentError # if Date.new raises an exception on an invalid date
-
4
instantiate_time_object(set_values).to_date # we instantiate Time object and convert it back to a date thus using Time's logic in handling invalid dates
-
end
-
end
-
-
1
def read_other(klass)
-
5
max_position = extract_max_param
-
5
positions = (1..max_position)
-
5
validate_missing_parameters!(positions)
-
-
3
set_values = values.values_at(*positions)
-
3
klass.new(*set_values)
-
end
-
-
# Checks whether some blank date parameter exists. Note that this is different
-
# than the validate_missing_parameters! method, since it just checks for blank
-
# positions instead of missing ones, and does not raise in case one blank position
-
# exists. The caller is responsible to handle the case of this returning true.
-
1
def blank_date_parameter?
-
98
(1..3).any? { |position| values[position].blank? }
-
end
-
-
# If some position is not provided, it errors out a missing parameter exception.
-
1
def validate_missing_parameters!(positions)
-
82
if missing_parameter = positions.detect { |position| !values.key?(position) }
-
6
raise ArgumentError.new("Missing Parameter - #{name}(#{missing_parameter})")
-
end
-
end
-
-
1
def extract_max_param(upper_cap = 100)
-
19
[values.keys.max, upper_cap].min
-
end
-
end
-
end
-
end
-
1
require 'active_support/core_ext/enumerable'
-
-
1
module ActiveRecord
-
# = Active Record Attribute Methods
-
1
module AttributeMethods
-
1
extend ActiveSupport::Concern
-
1
include ActiveModel::AttributeMethods
-
-
1
included do
-
3
include Read
-
3
include Write
-
3
include BeforeTypeCast
-
3
include Query
-
3
include PrimaryKey
-
3
include TimeZoneConversion
-
3
include Dirty
-
3
include Serialization
-
end
-
-
1
module ClassMethods
-
# Generates all the attribute related methods for columns in the database
-
# accessors, mutators and query methods.
-
1
def define_attribute_methods # :nodoc:
-
# Use a mutex; we don't want two thread simaltaneously trying to define
-
# attribute methods.
-
404
@attribute_methods_mutex.synchronize do
-
404
return if attribute_methods_generated?
-
351
superclass.define_attribute_methods unless self == base_class
-
351
super(column_names)
-
351
@attribute_methods_generated = true
-
end
-
end
-
-
1
def attribute_methods_generated? # :nodoc:
-
49495
@attribute_methods_generated ||= false
-
end
-
-
1
def undefine_attribute_methods # :nodoc:
-
235
super if attribute_methods_generated?
-
235
@attribute_methods_generated = false
-
end
-
-
# Raises a <tt>ActiveRecord::DangerousAttributeError</tt> exception when an
-
# \Active \Record method is defined in the model, otherwise +false+.
-
#
-
# class Person < ActiveRecord::Base
-
# def save
-
# 'already defined by Active Record'
-
# end
-
# end
-
#
-
# Person.instance_method_already_implemented?(:save)
-
# # => ActiveRecord::DangerousAttributeError: save is defined by ActiveRecord
-
#
-
# Person.instance_method_already_implemented?(:name)
-
# # => false
-
1
def instance_method_already_implemented?(method_name)
-
22524
if dangerous_attribute_method?(method_name)
-
2
raise DangerousAttributeError, "#{method_name} is defined by ActiveRecord"
-
end
-
-
22522
if superclass == Base
-
16762
super
-
else
-
# If B < A and A defines its own attribute method, then we don't want to overwrite that.
-
5760
defined = method_defined_within?(method_name, superclass, superclass.generated_attribute_methods)
-
5760
defined && !ActiveRecord::Base.method_defined?(method_name) || super
-
end
-
end
-
-
# A method name is 'dangerous' if it is already defined by Active Record, but
-
# not by any ancestors. (So 'puts' is not dangerous but 'save' is.)
-
1
def dangerous_attribute_method?(name) # :nodoc:
-
22524
method_defined_within?(name, Base)
-
end
-
-
1
def method_defined_within?(name, klass, sup = klass.superclass) # :nodoc:
-
28284
if klass.method_defined?(name) || klass.private_method_defined?(name)
-
6781
if sup.method_defined?(name) || sup.private_method_defined?(name)
-
5441
klass.instance_method(name).owner != sup.instance_method(name).owner
-
else
-
1340
true
-
end
-
else
-
21503
false
-
end
-
end
-
-
# Returns +true+ if +attribute+ is an attribute method and table exists,
-
# +false+ otherwise.
-
#
-
# class Person < ActiveRecord::Base
-
# end
-
#
-
# Person.attribute_method?('name') # => true
-
# Person.attribute_method?(:age=) # => true
-
# Person.attribute_method?(:nothing) # => false
-
1
def attribute_method?(attribute)
-
4
super || (table_exists? && column_names.include?(attribute.to_s.sub(/=$/, '')))
-
end
-
-
# Returns an array of column names as strings if it's not an abstract class and
-
# table exists. Otherwise it returns an empty array.
-
#
-
# class Person < ActiveRecord::Base
-
# end
-
#
-
# Person.attribute_names
-
# # => ["id", "created_at", "updated_at", "name", "age"]
-
1
def attribute_names
-
@attribute_names ||= if !abstract_class? && table_exists?
-
1
column_names
-
else
-
2
[]
-
3
end
-
end
-
end
-
-
# If we haven't generated any methods yet, generate them, then
-
# see if we've created the method we're looking for.
-
1
def method_missing(method, *args, &block) # :nodoc:
-
178
unless self.class.attribute_methods_generated?
-
125
self.class.define_attribute_methods
-
-
125
if respond_to_without_attributes?(method)
-
123
send(method, *args, &block)
-
else
-
2
super
-
end
-
else
-
53
super
-
end
-
end
-
-
1
def attribute_missing(match, *args, &block) # :nodoc:
-
21
if self.class.columns_hash[match.attr_name]
-
1
ActiveSupport::Deprecation.warn(
-
"The method `#{match.method_name}', matching the attribute `#{match.attr_name}' has " \
-
"dispatched through method_missing. This shouldn't happen, because `#{match.attr_name}' " \
-
"is a column of the table. If this error has happened through normal usage of Active " \
-
"Record (rather than through your own code or external libraries), please report it as " \
-
"a bug."
-
)
-
end
-
-
21
super
-
end
-
-
# A Person object with a name attribute can ask <tt>person.respond_to?(:name)</tt>,
-
# <tt>person.respond_to?(:name=)</tt>, and <tt>person.respond_to?(:name?)</tt>
-
# which will all return +true+. It also define the attribute methods if they have
-
# not been generated.
-
#
-
# class Person < ActiveRecord::Base
-
# end
-
#
-
# person = Person.new
-
# person.respond_to(:name) # => true
-
# person.respond_to(:name=) # => true
-
# person.respond_to(:name?) # => true
-
# person.respond_to('age') # => true
-
# person.respond_to('age=') # => true
-
# person.respond_to('age?') # => true
-
# person.respond_to(:nothing) # => false
-
1
def respond_to?(name, include_private = false)
-
48676
self.class.define_attribute_methods unless self.class.attribute_methods_generated?
-
48676
super
-
end
-
-
# Returns +true+ if the given attribute is in the attributes hash, otherwise +false+.
-
#
-
# class Person < ActiveRecord::Base
-
# end
-
#
-
# person = Person.new
-
# person.has_attribute?(:name) # => true
-
# person.has_attribute?('age') # => true
-
# person.has_attribute?(:nothing) # => false
-
1
def has_attribute?(attr_name)
-
5949
@attributes.has_key?(attr_name.to_s)
-
end
-
-
# Returns an array of names for the attributes available on this object.
-
#
-
# class Person < ActiveRecord::Base
-
# end
-
#
-
# person = Person.new
-
# person.attribute_names
-
# # => ["id", "created_at", "updated_at", "name", "age"]
-
1
def attribute_names
-
3942
@attributes.keys
-
end
-
-
# Returns a hash of all the attributes with their names as keys and the values of the attributes as values.
-
#
-
# class Person < ActiveRecord::Base
-
# end
-
#
-
# person = Person.create(name: 'Francesco', age: 22)
-
# person.attributes
-
# # => {"id"=>3, "created_at"=>Sun, 21 Oct 2012 04:53:04, "updated_at"=>Sun, 21 Oct 2012 04:53:04, "name"=>"Francesco", "age"=>22}
-
1
def attributes
-
3482
attribute_names.each_with_object({}) { |name, attrs|
-
23905
attrs[name] = read_attribute(name)
-
}
-
end
-
-
# Returns an <tt>#inspect</tt>-like string for the value of the
-
# attribute +attr_name+. String attributes are truncated upto 50
-
# characters, and Date and Time attributes are returned in the
-
# <tt>:db</tt> format. Other attributes return the value of
-
# <tt>#inspect</tt> without modification.
-
#
-
# person = Person.create!(name: 'David Heinemeier Hansson ' * 3)
-
#
-
# person.attribute_for_inspect(:name)
-
# # => "\"David Heinemeier Hansson David Heinemeier Hansson D...\""
-
#
-
# person.attribute_for_inspect(:created_at)
-
# # => "\"2012-10-22 00:15:07\""
-
1
def attribute_for_inspect(attr_name)
-
772
value = read_attribute(attr_name)
-
-
772
if value.is_a?(String) && value.length > 50
-
1
"#{value[0..50]}...".inspect
-
771
elsif value.is_a?(Date) || value.is_a?(Time)
-
17
%("#{value.to_s(:db)}")
-
else
-
754
value.inspect
-
end
-
end
-
-
# Returns +true+ if the specified +attribute+ has been set by the user or by a
-
# database load and is neither +nil+ nor <tt>empty?</tt> (the latter only applies
-
# to objects that respond to <tt>empty?</tt>, most notably Strings). Otherwise, +false+.
-
# Note that it always returns +true+ with boolean attributes.
-
#
-
# class Task < ActiveRecord::Base
-
# end
-
#
-
# person = Task.new(title: '', is_done: false)
-
# person.attribute_present?(:title) # => false
-
# person.attribute_present?(:is_done) # => true
-
# person.name = 'Francesco'
-
# person.is_done = true
-
# person.attribute_present?(:title) # => true
-
# person.attribute_present?(:is_done) # => true
-
1
def attribute_present?(attribute)
-
711
value = read_attribute(attribute)
-
711
!value.nil? && !(value.respond_to?(:empty?) && value.empty?)
-
end
-
-
# Returns the column object for the named attribute. Returns +nil+ if the
-
# named attribute not exists.
-
#
-
# class Person < ActiveRecord::Base
-
# end
-
#
-
# person = Person.new
-
# person.column_for_attribute(:name) # the result depends on the ConnectionAdapter
-
# # => #<ActiveRecord::ConnectionAdapters::SQLite3Column:0x007ff4ab083980 @name="name", @sql_type="varchar(255)", @null=true, ...>
-
#
-
# person.column_for_attribute(:nothing)
-
# # => nil
-
1
def column_for_attribute(name)
-
# FIXME: should this return a null object for columns that don't exist?
-
42368
self.class.columns_hash[name.to_s]
-
end
-
-
# Returns the value of the attribute identified by <tt>attr_name</tt> after it has been typecast (for example,
-
# "2004-12-12" in a data column is cast to a date object, like Date.new(2004, 12, 12)). It raises
-
# <tt>ActiveModel::MissingAttributeError</tt> if the identified attribute is missing.
-
#
-
# Alias for the <tt>read_attribute</tt> method.
-
#
-
# class Person < ActiveRecord::Base
-
# belongs_to :organization
-
# end
-
#
-
# person = Person.new(name: 'Francesco', age: '22')
-
# person[:name] # => "Francesco"
-
# person[:age] # => 22
-
#
-
# person = Person.select('id').first
-
# person[:name] # => ActiveModel::MissingAttributeError: missing attribute: name
-
# person[:organization_id] # => ActiveModel::MissingAttributeError: missing attribute: organization_id
-
1
def [](attr_name)
-
14947
read_attribute(attr_name) { |n| missing_attribute(n, caller) }
-
end
-
-
# Updates the attribute identified by <tt>attr_name</tt> with the specified +value+.
-
# (Alias for the protected <tt>write_attribute</tt> method).
-
#
-
# class Person < ActiveRecord::Base
-
# end
-
#
-
# person = Person.new
-
# person[:age] = '22'
-
# person[:age] # => 22
-
# person[:age] # => Fixnum
-
1
def []=(attr_name, value)
-
2553
write_attribute(attr_name, value)
-
end
-
-
1
protected
-
-
1
def clone_attributes(reader_method = :read_attribute, attributes = {}) # :nodoc:
-
25
attribute_names.each do |name|
-
330
attributes[name] = clone_attribute_value(reader_method, name)
-
end
-
25
attributes
-
end
-
-
1
def clone_attribute_value(reader_method, attribute_name) # :nodoc:
-
14197
value = send(reader_method, attribute_name)
-
14197
value.duplicable? ? value.clone : value
-
rescue TypeError, NoMethodError
-
value
-
end
-
-
1
def arel_attributes_with_values_for_create(attribute_names) # :nodoc:
-
2321
arel_attributes_with_values(attributes_for_create(attribute_names))
-
end
-
-
1
def arel_attributes_with_values_for_update(attribute_names) # :nodoc:
-
609
arel_attributes_with_values(attributes_for_update(attribute_names))
-
end
-
-
1
def attribute_method?(attr_name) # :nodoc:
-
8794
defined?(@attributes) && @attributes.include?(attr_name)
-
end
-
-
1
private
-
-
# Returns a Hash of the Arel::Attributes and attribute values that have been
-
# type casted for use in an Arel insert/update method.
-
1
def arel_attributes_with_values(attribute_names)
-
2930
attrs = {}
-
2930
arel_table = self.class.arel_table
-
-
2930
attribute_names.each do |name|
-
6428
attrs[arel_table[name]] = typecasted_attribute_value(name)
-
end
-
2929
attrs
-
end
-
-
# Filters the primary keys and readonly attributes from the attribute names.
-
1
def attributes_for_update(attribute_names)
-
609
attribute_names.select do |name|
-
775
column_for_attribute(name) && !pk_attribute?(name) && !readonly_attribute?(name)
-
end
-
end
-
-
# Filters out the primary keys, from the attribute names, when the primary
-
# key is to be generated (e.g. the id attribute has no value).
-
1
def attributes_for_create(attribute_names)
-
2321
attribute_names.select do |name|
-
5664
column_for_attribute(name) && !(pk_attribute?(name) && id.nil?)
-
end
-
end
-
-
1
def readonly_attribute?(name)
-
773
self.class.readonly_attributes.include?(name)
-
end
-
-
1
def pk_attribute?(name)
-
6439
column_for_attribute(name).primary
-
end
-
-
1
def typecasted_attribute_value(name)
-
# FIXME: we need @attributes to be used consistently.
-
# If the values stored in @attributes were already typecasted, this code
-
# could be simplified
-
6085
read_attribute(name)
-
end
-
end
-
end
-
1
module ActiveRecord
-
1
module AttributeMethods
-
# = Active Record Attribute Methods Before Type Cast
-
#
-
# <tt>ActiveRecord::AttributeMethods::BeforeTypeCast</tt> provides a way to
-
# read the value of the attributes before typecasting and deserialization.
-
#
-
# class Task < ActiveRecord::Base
-
# end
-
#
-
# task = Task.new(id: '1', completed_on: '2012-10-21')
-
# task.id # => 1
-
# task.completed_on # => Sun, 21 Oct 2012
-
#
-
# task.attributes_before_type_cast
-
# # => {"id"=>"1", "completed_on"=>"2012-10-21", ... }
-
# task.read_attribute_before_type_cast('id') # => "1"
-
# task.read_attribute_before_type_cast('completed_on') # => "2012-10-21"
-
#
-
# In addition to #read_attribute_before_type_cast and #attributes_before_type_cast,
-
# it declares a method for all attributes with the <tt>*_before_type_cast</tt>
-
# suffix.
-
#
-
# task.id_before_type_cast # => "1"
-
# task.completed_on_before_type_cast # => "2012-10-21"
-
1
module BeforeTypeCast
-
1
extend ActiveSupport::Concern
-
-
1
included do
-
3
attribute_method_suffix "_before_type_cast"
-
end
-
-
# Returns the value of the attribute identified by +attr_name+ before
-
# typecasting and deserialization.
-
#
-
# class Task < ActiveRecord::Base
-
# end
-
#
-
# task = Task.new(id: '1', completed_on: '2012-10-21')
-
# task.read_attribute('id') # => 1
-
# task.read_attribute_before_type_cast('id') # => '1'
-
# task.read_attribute('completed_on') # => Sun, 21 Oct 2012
-
# task.read_attribute_before_type_cast('completed_on') # => "2012-10-21"
-
1
def read_attribute_before_type_cast(attr_name)
-
346
@attributes[attr_name]
-
end
-
-
# Returns a hash of attributes before typecasting and deserialization.
-
#
-
# class Task < ActiveRecord::Base
-
# end
-
#
-
# task = Task.new(title: nil, is_done: true, completed_on: '2012-10-21')
-
# task.attributes
-
# # => {"id"=>nil, "title"=>nil, "is_done"=>true, "completed_on"=>Sun, 21 Oct 2012, "created_at"=>nil, "updated_at"=>nil}
-
# task.attributes_before_type_cast
-
# # => {"id"=>nil, "title"=>nil, "is_done"=>true, "completed_on"=>"2012-10-21", "created_at"=>nil, "updated_at"=>nil}
-
1
def attributes_before_type_cast
-
3
@attributes
-
end
-
-
1
private
-
-
# Handle *_before_type_cast for method_missing.
-
1
def attribute_before_type_cast(attribute_name)
-
13
read_attribute_before_type_cast(attribute_name)
-
end
-
end
-
end
-
end
-
1
require 'active_support/core_ext/module/attribute_accessors'
-
1
require 'active_support/deprecation'
-
-
1
module ActiveRecord
-
1
module AttributeMethods
-
1
module Dirty # :nodoc:
-
1
extend ActiveSupport::Concern
-
-
1
include ActiveModel::Dirty
-
-
1
included do
-
3
if self < ::ActiveRecord::Timestamp
-
raise "You cannot include Dirty after Timestamp"
-
end
-
-
3
class_attribute :partial_writes, instance_writer: false
-
3
self.partial_writes = true
-
-
4
def self.partial_updates=(v); self.partial_writes = v; end
-
5
def self.partial_updates?; partial_writes?; end
-
5
def self.partial_updates; partial_writes; end
-
-
3
ActiveSupport::Deprecation.deprecate_methods(
-
singleton_class,
-
:partial_updates= => :partial_writes=,
-
:partial_updates? => :partial_writes?,
-
:partial_updates => :partial_writes
-
)
-
end
-
-
# Attempts to +save+ the record and clears changed attributes if successful.
-
1
def save(*)
-
1708
if status = super
-
1582
@previously_changed = changes
-
1582
@changed_attributes.clear
-
end
-
1682
status
-
end
-
-
# Attempts to <tt>save!</tt> the record and clears changed attributes if successful.
-
1
def save!(*)
-
1383
super.tap do
-
1322
@previously_changed = changes
-
1322
@changed_attributes.clear
-
end
-
end
-
-
# <tt>reload</tt> the record and clears changed attributes.
-
1
def reload(*)
-
447
super.tap do
-
442
@previously_changed.clear
-
442
@changed_attributes.clear
-
end
-
end
-
-
1
private
-
# Wrap write_attribute to remember original attribute value.
-
1
def write_attribute(attr, value)
-
14510
attr = attr.to_s
-
-
# The attribute already has an unsaved change.
-
14510
if attribute_changed?(attr)
-
643
old = @changed_attributes[attr]
-
643
@changed_attributes.delete(attr) unless _field_changed?(attr, old, value)
-
else
-
13867
old = clone_attribute_value(:read_attribute, attr)
-
13867
@changed_attributes[attr] = old if _field_changed?(attr, old, value)
-
end
-
-
# Carry on.
-
14510
super(attr, value)
-
end
-
-
1
def update(*)
-
612
partial_writes? ? super(keys_for_partial_write) : super
-
end
-
-
1
def create(*)
-
2321
partial_writes? ? super(keys_for_partial_write) : super
-
end
-
-
# Serialized attributes should always be written in case they've been
-
# changed in place.
-
1
def keys_for_partial_write
-
2929
changed | (attributes.keys & self.class.serialized_attributes.keys)
-
end
-
-
1
def _field_changed?(attr, old, value)
-
14840
if column = column_for_attribute(attr)
-
if column.number? && (changes_from_nil_to_empty_string?(column, old, value) ||
-
14826
changes_from_zero_to_string?(old, value))
-
275
value = nil
-
else
-
14551
value = column.type_cast(value)
-
end
-
end
-
-
14840
old != value
-
end
-
-
1
def changes_from_nil_to_empty_string?(column, old, value)
-
# For nullable numeric columns, NULL gets stored in database for blank (i.e. '') values.
-
# Hence we don't record it as a change if the value changes from nil to ''.
-
# If an old value of 0 is set to '' we want this to get changed to nil as otherwise it'll
-
# be typecast back to 0 (''.to_i => 0)
-
7749
column.null && (old.nil? || old == 0) && value.blank?
-
end
-
-
1
def changes_from_zero_to_string?(old, value)
-
# For columns with old 0 and value non-empty string
-
7488
old == 0 && value.is_a?(String) && value.present? && value != '0'
-
end
-
end
-
end
-
end
-
1
module ActiveRecord
-
1
module AttributeMethods
-
1
module Query
-
1
extend ActiveSupport::Concern
-
-
1
included do
-
3
attribute_method_suffix "?"
-
end
-
-
1
def query_attribute(attr_name)
-
137
value = read_attribute(attr_name) { |n| missing_attribute(n, caller) }
-
-
135
case value
-
64
when true then true
-
60
when false, nil then false
-
else
-
11
column = self.class.columns_hash[attr_name]
-
11
if column.nil?
-
4
if Numeric === value || value !~ /[^0-9]/
-
2
!value.to_i.zero?
-
else
-
2
return false if ActiveRecord::ConnectionAdapters::Column::FALSE_VALUES.include?(value)
-
2
!value.blank?
-
end
-
7
elsif column.number?
-
4
!value.zero?
-
else
-
3
!value.blank?
-
end
-
end
-
end
-
-
1
private
-
# Handle *? for method_missing.
-
1
def attribute?(attribute_name)
-
136
query_attribute(attribute_name)
-
end
-
end
-
end
-
end
-
1
module ActiveRecord
-
1
module AttributeMethods
-
1
module Read
-
1
extend ActiveSupport::Concern
-
-
1
ATTRIBUTE_TYPES_CACHED_BY_DEFAULT = [:datetime, :timestamp, :time, :date]
-
-
1
included do
-
3
class_attribute :attribute_types_cached_by_default, instance_writer: false
-
3
self.attribute_types_cached_by_default = ATTRIBUTE_TYPES_CACHED_BY_DEFAULT
-
end
-
-
1
module ClassMethods
-
# +cache_attributes+ allows you to declare which converted attribute
-
# values should be cached. Usually caching only pays off for attributes
-
# with expensive conversion methods, like time related columns (e.g.
-
# +created_at+, +updated_at+).
-
1
def cache_attributes(*attribute_names)
-
2
cached_attributes.merge attribute_names.map { |attr| attr.to_s }
-
end
-
-
# Returns the attributes which are cached. By default time related columns
-
# with datatype <tt>:datetime, :timestamp, :time, :date</tt> are cached.
-
1
def cached_attributes
-
46496
@cached_attributes ||= columns.select { |c| cacheable_column?(c) }.map { |col| col.name }.to_set
-
end
-
-
# Returns +true+ if the provided attribute is being cached.
-
1
def cache_attribute?(attr_name)
-
42567
cached_attributes.include?(attr_name)
-
end
-
-
1
protected
-
-
# We want to generate the methods via module_eval rather than define_method,
-
# because define_method is slower on dispatch and uses more memory (because it
-
# creates a closure).
-
#
-
# But sometimes the database might return columns with characters that are not
-
# allowed in normal method names (like 'my_column(omg)'. So to work around this
-
# we first define with the __temp__ identifier, and then use alias method to
-
# rename it to what we want.
-
1
def define_method_attribute(attr_name)
-
2454
generated_attribute_methods.module_eval <<-STR, __FILE__, __LINE__ + 1
-
def __temp__
-
read_attribute('#{attr_name}') { |n| missing_attribute(n, caller) }
-
end
-
alias_method '#{attr_name}', :__temp__
-
undef_method :__temp__
-
STR
-
end
-
-
1
private
-
-
1
def cacheable_column?(column)
-
1975
if attribute_types_cached_by_default == ATTRIBUTE_TYPES_CACHED_BY_DEFAULT
-
1975
! serialized_attributes.include? column.name
-
else
-
attribute_types_cached_by_default.include?(column.type)
-
end
-
end
-
end
-
-
# Returns the value of the attribute identified by <tt>attr_name</tt> after
-
# it has been typecast (for example, "2004-12-12" in a data column is cast
-
# to a date object, like Date.new(2004, 12, 12)).
-
1
def read_attribute(attr_name)
-
# If it's cached, just return it
-
# We use #[] first as a perf optimization for non-nil values. See https://gist.github.com/3552829.
-
114909
name = attr_name.to_s
-
@attributes_cache[name] || @attributes_cache.fetch(name) {
-
43058
column = @columns_hash.fetch(name) {
-
return @attributes.fetch(name) {
-
399
if name == 'id' && self.class.primary_key != name
-
1
read_attribute(self.class.primary_key)
-
end
-
501
}
-
}
-
-
42557
value = @attributes.fetch(name) {
-
7
return block_given? ? yield(name) : nil
-
}
-
-
42550
if self.class.cache_attribute?(name)
-
41250
@attributes_cache[name] = column.type_cast(value)
-
else
-
1300
column.type_cast value
-
end
-
114909
}
-
end
-
-
1
private
-
-
1
def attribute(attribute_name)
-
13
read_attribute(attribute_name)
-
end
-
end
-
end
-
end
-
1
module ActiveRecord
-
1
module AttributeMethods
-
1
module Serialization
-
1
extend ActiveSupport::Concern
-
-
1
included do
-
# Returns a hash of all the attributes that have been specified for
-
# serialization as keys and their class restriction as values.
-
3
class_attribute :serialized_attributes, instance_accessor: false
-
3
self.serialized_attributes = {}
-
end
-
-
1
module ClassMethods
-
# If you have an attribute that needs to be saved to the database as an
-
# object, and retrieved as the same object, then specify the name of that
-
# attribute using this method and it will be handled automatically. The
-
# serialization is done through YAML. If +class_name+ is specified, the
-
# serialized object must be of that class on retrieval or
-
# <tt>SerializationTypeMismatch</tt> will be raised.
-
#
-
# ==== Parameters
-
#
-
# * +attr_name+ - The field name that should be serialized.
-
# * +class_name+ - Optional, class name that the object type should be equal to.
-
#
-
# ==== Example
-
#
-
# # Serialize a preferences attribute.
-
# class User < ActiveRecord::Base
-
# serialize :preferences
-
# end
-
1
def serialize(attr_name, class_name = Object)
-
44
include Behavior
-
-
132
coder = if [:load, :dump].all? { |x| class_name.respond_to?(x) }
-
7
class_name
-
else
-
37
Coders::YAMLColumn.new(class_name)
-
end
-
-
# merge new serialized attribute and create new hash to ensure that each class in inheritance hierarchy
-
# has its own hash of own serialized attributes
-
44
self.serialized_attributes = serialized_attributes.merge(attr_name.to_s => coder)
-
end
-
end
-
-
1
def serialized_attributes
-
1
message = "Instance level serialized_attributes method is deprecated, please use class level method."
-
1
ActiveSupport::Deprecation.warn message
-
1
defined?(@serialized_attributes) ? @serialized_attributes : self.class.serialized_attributes
-
end
-
-
1
class Type # :nodoc:
-
1
def initialize(column)
-
1140
@column = column
-
end
-
-
1
def type_cast(value)
-
1163
value.unserialized_value
-
end
-
-
1
def type
-
3
@column.type
-
end
-
end
-
-
1
class Attribute < Struct.new(:coder, :value, :state) # :nodoc:
-
1
def unserialized_value
-
1184
state == :serialized ? unserialize : value
-
end
-
-
1
def serialized_value
-
343
state == :unserialized ? serialize : value
-
end
-
-
1
def unserialize
-
645
self.state = :unserialized
-
645
self.value = coder.load(value)
-
end
-
-
1
def serialize
-
343
self.state = :serialized
-
343
self.value = coder.dump(value)
-
end
-
end
-
-
# This is only added to the model when serialize is called, which
-
# ensures we do not make things slower when serialization is not used.
-
1
module Behavior #:nodoc:
-
1
extend ActiveSupport::Concern
-
-
1
module ClassMethods
-
1
def initialize_attributes(attributes, options = {})
-
3028
serialized = (options.delete(:serialized) { true }) ? :serialized : :unserialized
-
1522
super(attributes, options)
-
-
1522
serialized_attributes.each do |key, coder|
-
1601
if attributes.key?(key)
-
1567
attributes[key] = Attribute.new(coder, attributes[key], serialized)
-
end
-
end
-
-
1522
attributes
-
end
-
end
-
-
1
def type_cast_attribute_for_write(column, value)
-
2261
if column && coder = self.class.serialized_attributes[column.name]
-
135
Attribute.new(coder, value, :unserialized)
-
else
-
2126
super
-
end
-
end
-
-
1
def read_attribute_before_type_cast(attr_name)
-
275
if self.class.serialized_attributes.include?(attr_name)
-
19
super.unserialized_value
-
else
-
256
super
-
end
-
end
-
-
1
def attributes_before_type_cast
-
2
super.dup.tap do |attributes|
-
2
self.class.serialized_attributes.each_key do |key|
-
2
if attributes.key?(key)
-
2
attributes[key] = attributes[key].unserialized_value
-
end
-
end
-
end
-
end
-
-
1
def typecasted_attribute_value(name)
-
1346
if self.class.serialized_attributes.include?(name)
-
343
@attributes[name].serialized_value
-
else
-
1003
super
-
end
-
end
-
end
-
end
-
end
-
end
-
1
module ActiveRecord
-
1
module AttributeMethods
-
1
module TimeZoneConversion
-
1
class Type # :nodoc:
-
1
def initialize(column)
-
76
@column = column
-
end
-
-
1
def type_cast(value)
-
98
value = @column.type_cast(value)
-
98
value.acts_like?(:time) ? value.in_time_zone : value
-
end
-
-
1
def type
-
@column.type
-
end
-
end
-
-
1
extend ActiveSupport::Concern
-
-
1
included do
-
3
mattr_accessor :time_zone_aware_attributes, instance_writer: false
-
3
self.time_zone_aware_attributes = false
-
-
3
class_attribute :skip_time_zone_conversion_for_attributes, instance_writer: false
-
3
self.skip_time_zone_conversion_for_attributes = []
-
end
-
-
1
module ClassMethods
-
1
protected
-
# Defined for all +datetime+ and +timestamp+ attributes when +time_zone_aware_attributes+ are enabled.
-
# This enhanced write method will automatically convert the time passed to it to the zone stored in Time.zone.
-
1
def define_method_attribute=(attr_name)
-
2440
if create_time_zone_conversion_attribute?(attr_name, columns_hash[attr_name])
-
47
method_body, line = <<-EOV, __LINE__ + 1
-
def #{attr_name}=(original_time)
-
time = original_time
-
unless time.acts_like?(:time)
-
time = time.is_a?(String) ? Time.zone.parse(time) : time.to_time rescue time
-
end
-
zoned_time = time && time.in_time_zone rescue nil
-
rounded_time = round_usec(zoned_time)
-
rounded_value = round_usec(read_attribute("#{attr_name}"))
-
if (rounded_value != rounded_time) || (!rounded_value && original_time)
-
write_attribute("#{attr_name}", original_time)
-
#{attr_name}_will_change!
-
@attributes_cache["#{attr_name}"] = zoned_time
-
end
-
end
-
EOV
-
47
generated_attribute_methods.module_eval(method_body, __FILE__, line)
-
else
-
2393
super
-
end
-
end
-
-
1
private
-
1
def create_time_zone_conversion_attribute?(name, column)
-
time_zone_aware_attributes &&
-
82159
!self.skip_time_zone_conversion_for_attributes.include?(name.to_sym) &&
-
[:datetime, :timestamp].include?(column.type)
-
end
-
end
-
-
1
private
-
1
def round_usec(value)
-
130
return unless value
-
66
value.change(:usec => 0)
-
end
-
end
-
end
-
end
-
1
module ActiveRecord
-
1
module AttributeMethods
-
1
module Write
-
1
extend ActiveSupport::Concern
-
-
1
included do
-
3
attribute_method_suffix "="
-
end
-
-
1
module ClassMethods
-
1
protected
-
1
def define_method_attribute=(attr_name)
-
2393
if attr_name =~ ActiveModel::AttributeMethods::NAME_COMPILABLE_REGEXP
-
2392
generated_attribute_methods.module_eval("def #{attr_name}=(new_value); write_attribute('#{attr_name}', new_value); end", __FILE__, __LINE__)
-
else
-
1
generated_attribute_methods.send(:define_method, "#{attr_name}=") do |new_value|
-
1
write_attribute(attr_name, new_value)
-
end
-
end
-
end
-
end
-
-
# Updates the attribute identified by <tt>attr_name</tt> with the
-
# specified +value+. Empty strings for fixnum and float columns are
-
# turned into +nil+.
-
1
def write_attribute(attr_name, value)
-
14591
attr_name = attr_name.to_s
-
14591
attr_name = self.class.primary_key if attr_name == 'id' && self.class.primary_key
-
14591
@attributes_cache.delete(attr_name)
-
14591
column = column_for_attribute(attr_name)
-
-
# If we're dealing with a binary column, write the data to the cache
-
# so we don't attempt to typecast multiple times.
-
14591
if column && column.binary?
-
37
@attributes_cache[attr_name] = value
-
end
-
-
14591
if column || @attributes.has_key?(attr_name)
-
14591
@attributes[attr_name] = type_cast_attribute_for_write(column, value)
-
else
-
raise ActiveModel::MissingAttributeError, "can't write unknown attribute `#{attr_name}'"
-
end
-
end
-
1
alias_method :raw_write_attribute, :write_attribute
-
-
1
private
-
# Handle *= for method_missing.
-
1
def attribute=(attribute_name, value)
-
2
write_attribute(attribute_name, value)
-
end
-
-
1
def type_cast_attribute_for_write(column, value)
-
14456
return value unless column
-
-
14442
column.type_cast_for_write value
-
end
-
end
-
end
-
end
-
1
module ActiveRecord
-
# = Active Record Autosave Association
-
#
-
# +AutosaveAssociation+ is a module that takes care of automatically saving
-
# associated records when their parent is saved. In addition to saving, it
-
# also destroys any associated records that were marked for destruction.
-
# (See +mark_for_destruction+ and <tt>marked_for_destruction?</tt>).
-
#
-
# Saving of the parent, its associations, and the destruction of marked
-
# associations, all happen inside a transaction. This should never leave the
-
# database in an inconsistent state.
-
#
-
# If validations for any of the associations fail, their error messages will
-
# be applied to the parent.
-
#
-
# Note that it also means that associations marked for destruction won't
-
# be destroyed directly. They will however still be marked for destruction.
-
#
-
# Note that <tt>:autosave => false</tt> is not same as not declaring <tt>:autosave</tt>.
-
# When the <tt>:autosave</tt> option is not present new associations are saved.
-
#
-
# == Validation
-
#
-
# Children records are validated unless <tt>:validate</tt> is +false+.
-
#
-
# == Callbacks
-
#
-
# Association with autosave option defines several callbacks on your
-
# model (before_save, after_create, after_update). Please note that
-
# callbacks are executed in the order they were defined in
-
# model. You should avoid modifying the association content, before
-
# autosave callbacks are executed. Placing your callbacks after
-
# associations is usually a good practice.
-
#
-
# == Examples
-
#
-
# === One-to-one Example
-
#
-
# class Post
-
# has_one :author, :autosave => true
-
# end
-
#
-
# Saving changes to the parent and its associated model can now be performed
-
# automatically _and_ atomically:
-
#
-
# post = Post.find(1)
-
# post.title # => "The current global position of migrating ducks"
-
# post.author.name # => "alloy"
-
#
-
# post.title = "On the migration of ducks"
-
# post.author.name = "Eloy Duran"
-
#
-
# post.save
-
# post.reload
-
# post.title # => "On the migration of ducks"
-
# post.author.name # => "Eloy Duran"
-
#
-
# Destroying an associated model, as part of the parent's save action, is as
-
# simple as marking it for destruction:
-
#
-
# post.author.mark_for_destruction
-
# post.author.marked_for_destruction? # => true
-
#
-
# Note that the model is _not_ yet removed from the database:
-
#
-
# id = post.author.id
-
# Author.find_by_id(id).nil? # => false
-
#
-
# post.save
-
# post.reload.author # => nil
-
#
-
# Now it _is_ removed from the database:
-
#
-
# Author.find_by_id(id).nil? # => true
-
#
-
# === One-to-many Example
-
#
-
# When <tt>:autosave</tt> is not declared new children are saved when their parent is saved:
-
#
-
# class Post
-
# has_many :comments # :autosave option is not declared
-
# end
-
#
-
# post = Post.new(:title => 'ruby rocks')
-
# post.comments.build(:body => 'hello world')
-
# post.save # => saves both post and comment
-
#
-
# post = Post.create(:title => 'ruby rocks')
-
# post.comments.build(:body => 'hello world')
-
# post.save # => saves both post and comment
-
#
-
# post = Post.create(:title => 'ruby rocks')
-
# post.comments.create(:body => 'hello world')
-
# post.save # => saves both post and comment
-
#
-
# When <tt>:autosave</tt> is true all children are saved, no matter whether they
-
# are new records or not:
-
#
-
# class Post
-
# has_many :comments, :autosave => true
-
# end
-
#
-
# post = Post.create(:title => 'ruby rocks')
-
# post.comments.create(:body => 'hello world')
-
# post.comments[0].body = 'hi everyone'
-
# post.save # => saves both post and comment, with 'hi everyone' as body
-
#
-
# Destroying one of the associated models as part of the parent's save action
-
# is as simple as marking it for destruction:
-
#
-
# post.comments.last.mark_for_destruction
-
# post.comments.last.marked_for_destruction? # => true
-
# post.comments.length # => 2
-
#
-
# Note that the model is _not_ yet removed from the database:
-
#
-
# id = post.comments.last.id
-
# Comment.find_by_id(id).nil? # => false
-
#
-
# post.save
-
# post.reload.comments.length # => 1
-
#
-
# Now it _is_ removed from the database:
-
#
-
# Comment.find_by_id(id).nil? # => true
-
-
1
module AutosaveAssociation
-
1
extend ActiveSupport::Concern
-
-
1
module AssociationBuilderExtension #:nodoc:
-
1
def build
-
615
model.send(:add_autosave_association_callbacks, reflection)
-
615
super
-
end
-
end
-
-
1
included do
-
1
Associations::Builder::Association.class_eval do
-
1
self.valid_options << :autosave
-
1
include AssociationBuilderExtension
-
end
-
end
-
-
1
module ClassMethods
-
1
private
-
-
1
def define_non_cyclic_method(name, reflection, &block)
-
854
define_method(name) do |*args|
-
37445
result = true; @_already_called ||= {}
-
# Loop prevention for validation of associations
-
37445
unless @_already_called[[name, reflection.name]]
-
37443
begin
-
37443
@_already_called[[name, reflection.name]]=true
-
37443
result = instance_eval(&block)
-
ensure
-
37443
@_already_called[[name, reflection.name]]=false
-
end
-
end
-
-
37435
result
-
end
-
end
-
-
# Adds validation and save callbacks for the association as specified by
-
# the +reflection+.
-
#
-
# For performance reasons, we don't check whether to validate at runtime.
-
# However the validation and callback methods are lazy and those methods
-
# get created when they are invoked for the very first time. However,
-
# this can change, for instance, when using nested attributes, which is
-
# called _after_ the association has been defined. Since we don't want
-
# the callbacks to get defined multiple times, there are guards that
-
# check if the save or validation methods have already been defined
-
# before actually defining them.
-
1
def add_autosave_association_callbacks(reflection)
-
708
save_method = :"autosave_associated_records_for_#{reflection.name}"
-
708
validation_method = :"validate_associated_records_for_#{reflection.name}"
-
708
collection = reflection.collection?
-
-
708
unless method_defined?(save_method)
-
608
if collection
-
374
before_save :before_save_collection_association
-
-
15944
define_non_cyclic_method(save_method, reflection) { save_collection_association(reflection) }
-
# Doesn't use after_save as that would save associations added in after_create/after_update twice
-
374
after_create save_method
-
374
after_update save_method
-
elsif reflection.macro == :has_one
-
3328
define_method(save_method) { save_has_one_association(reflection) }
-
# Configures two callbacks instead of a single after_save so that
-
# the model may rely on their execution order relative to its
-
# own callbacks.
-
#
-
# For example, given that after_creates run before after_saves, if
-
# we configured instead an after_save there would be no way to fire
-
# a custom after_create callback after the child association gets
-
# created.
-
83
after_create save_method
-
83
after_update save_method
-
else
-
4719
define_non_cyclic_method(save_method, reflection) { save_belongs_to_association(reflection) }
-
151
before_save save_method
-
end
-
end
-
-
708
if reflection.validate? && !method_defined?(validation_method)
-
329
method = (collection ? :validate_collection_association : :validate_single_association)
-
17634
define_non_cyclic_method(validation_method, reflection) { send(method, reflection) }
-
329
validate validation_method
-
end
-
end
-
end
-
-
# Reloads the attributes of the object as usual and clears <tt>marked_for_destruction</tt> flag.
-
1
def reload(options = nil)
-
447
@marked_for_destruction = false
-
447
super
-
end
-
-
# Marks this record to be destroyed as part of the parents save transaction.
-
# This does _not_ actually destroy the record instantly, rather child record will be destroyed
-
# when <tt>parent.save</tt> is called.
-
#
-
# Only useful if the <tt>:autosave</tt> option on the parent is enabled for this associated model.
-
1
def mark_for_destruction
-
97
@marked_for_destruction = true
-
end
-
-
# Returns whether or not this record will be destroyed as part of the parents save transaction.
-
#
-
# Only useful if the <tt>:autosave</tt> option on the parent is enabled for this associated model.
-
1
def marked_for_destruction?
-
932
@marked_for_destruction
-
end
-
-
# Returns whether or not this record has been changed in any way (including whether
-
# any of its nested autosave associations are likewise changed)
-
1
def changed_for_autosave?
-
438
new_record? || changed? || marked_for_destruction? || nested_records_changed_for_autosave?
-
end
-
-
1
private
-
-
# Returns the record for an association collection that should be validated
-
# or saved. If +autosave+ is +false+ only new records will be returned,
-
# unless the parent is/was a new record itself.
-
1
def associated_records_to_validate_or_save(association, new_record, autosave)
-
446
if new_record
-
173
association && association.target
-
273
elsif autosave
-
619
association.target.find_all { |record| record.changed_for_autosave? }
-
else
-
112
association.target.find_all { |record| record.new_record? }
-
end
-
end
-
-
# go through nested autosave associations that are loaded in memory (without loading
-
# any new ones), and return true if is changed for autosave
-
1
def nested_records_changed_for_autosave?
-
145
self.class.reflect_on_all_autosave_associations.any? do |reflection|
-
164
association = association_instance_get(reflection.name)
-
194
association && Array.wrap(association.target).any? { |a| a.changed_for_autosave? }
-
end
-
end
-
-
# Validate the association if <tt>:validate</tt> or <tt>:autosave</tt> is
-
# turned on for the association.
-
1
def validate_single_association(reflection)
-
2037
association = association_instance_get(reflection.name)
-
2037
record = association && association.reader
-
2037
association_valid?(reflection, record) if record
-
end
-
-
# Validate the associated records if <tt>:validate</tt> or
-
# <tt>:autosave</tt> is turned on for the association specified by
-
# +reflection+.
-
1
def validate_collection_association(reflection)
-
15268
if association = association_instance_get(reflection.name)
-
219
if records = associated_records_to_validate_or_save(association, new_record?, reflection.options[:autosave])
-
474
records.each { |record| association_valid?(reflection, record) }
-
end
-
end
-
end
-
-
# Returns whether or not the association is valid and applies any errors to
-
# the parent, <tt>self</tt>, if it wasn't. Skips any <tt>:autosave</tt>
-
# enabled records if they're marked_for_destruction? or destroyed.
-
1
def association_valid?(reflection, record)
-
401
return true if record.destroyed? || record.marked_for_destruction?
-
-
337
unless valid = record.valid?(validation_context)
-
62
if reflection.options[:autosave]
-
44
record.errors.each do |attribute, message|
-
48
attribute = "#{reflection.name}.#{attribute}"
-
48
errors[attribute] << message
-
48
errors[attribute].uniq!
-
end
-
else
-
18
errors.add(reflection.name)
-
end
-
end
-
337
valid
-
end
-
-
# Is used as a before_save callback to check while saving a collection
-
# association whether or not the parent was a new record before saving.
-
1
def before_save_collection_association
-
2092
@new_record_before_save = new_record?
-
2092
true
-
end
-
-
# Saves any new associated records, or all loaded autosave associations if
-
# <tt>:autosave</tt> is enabled on the association.
-
#
-
# In addition, it destroys all children that were marked for destruction
-
# with mark_for_destruction.
-
#
-
# This all happens inside a transaction, _if_ the Transactions module is included into
-
# ActiveRecord::Base after the AutosaveAssociation module, which it does by default.
-
1
def save_collection_association(reflection)
-
15570
if association = association_instance_get(reflection.name)
-
227
autosave = reflection.options[:autosave]
-
-
227
if records = associated_records_to_validate_or_save(association, @new_record_before_save, autosave)
-
227
records_to_destroy = []
-
227
records.each do |record|
-
253
next if record.destroyed?
-
-
253
saved = true
-
-
253
if autosave && record.marked_for_destruction?
-
33
records_to_destroy << record
-
elsif autosave != false && (@new_record_before_save || record.new_record?)
-
145
if autosave
-
32
saved = association.insert_record(record, false)
-
else
-
113
association.insert_record(record) unless reflection.nested?
-
end
-
elsif autosave
-
74
saved = record.save(:validate => false)
-
end
-
-
251
raise ActiveRecord::Rollback unless saved
-
end
-
-
221
records_to_destroy.each do |record|
-
32
association.destroy(record)
-
end
-
end
-
-
# reconstruct the scope now that we know the owner's id
-
219
association.send(:reset_scope) if association.respond_to?(:reset_scope)
-
end
-
end
-
-
# Saves the associated record if it's new or <tt>:autosave</tt> is enabled
-
# on the association.
-
#
-
# In addition, it will destroy the association if it was marked for
-
# destruction with mark_for_destruction.
-
#
-
# This all happens inside a transaction, _if_ the Transactions module is included into
-
# ActiveRecord::Base after the AutosaveAssociation module, which it does by default.
-
1
def save_has_one_association(reflection)
-
3245
association = association_instance_get(reflection.name)
-
3245
record = association && association.load_target
-
3245
if record && !record.destroyed?
-
78
autosave = reflection.options[:autosave]
-
-
78
if autosave && record.marked_for_destruction?
-
9
record.destroy
-
else
-
69
key = reflection.options[:primary_key] ? send(reflection.options[:primary_key]) : id
-
69
if autosave != false && (new_record? || record.new_record? || record[reflection.foreign_key] != key || autosave)
-
61
unless reflection.through_reflection
-
59
record[reflection.foreign_key] = key
-
end
-
-
61
saved = record.save(:validate => !autosave)
-
59
raise ActiveRecord::Rollback if !saved && autosave
-
58
saved
-
end
-
end
-
end
-
end
-
-
# Saves the associated record if it's new or <tt>:autosave</tt> is enabled.
-
#
-
# In addition, it will destroy the association if it was marked for destruction.
-
1
def save_belongs_to_association(reflection)
-
4568
association = association_instance_get(reflection.name)
-
4568
record = association && association.load_target
-
4568
if record && !record.destroyed?
-
204
autosave = reflection.options[:autosave]
-
-
204
if autosave && record.marked_for_destruction?
-
10
self[reflection.foreign_key] = nil
-
10
record.destroy
-
194
elsif autosave != false
-
193
saved = record.save(:validate => !autosave) if record.new_record? || (autosave && record.changed_for_autosave?)
-
-
191
if association.updated?
-
174
association_id = record.send(reflection.options[:primary_key] || :id)
-
174
self[reflection.foreign_key] = association_id
-
174
association.loaded!
-
end
-
-
191
saved if autosave
-
end
-
end
-
end
-
end
-
end
-
1
require 'yaml'
-
1
require 'set'
-
1
require 'active_support/benchmarkable'
-
1
require 'active_support/dependencies'
-
1
require 'active_support/descendants_tracker'
-
1
require 'active_support/time'
-
1
require 'active_support/core_ext/class/attribute_accessors'
-
1
require 'active_support/core_ext/class/delegating_attributes'
-
1
require 'active_support/core_ext/array/extract_options'
-
1
require 'active_support/core_ext/hash/deep_merge'
-
1
require 'active_support/core_ext/hash/slice'
-
1
require 'active_support/core_ext/string/behavior'
-
1
require 'active_support/core_ext/kernel/singleton_class'
-
1
require 'active_support/core_ext/module/introspection'
-
1
require 'active_support/core_ext/object/duplicable'
-
1
require 'arel'
-
1
require 'active_record/errors'
-
1
require 'active_record/log_subscriber'
-
1
require 'active_record/explain_subscriber'
-
-
1
module ActiveRecord #:nodoc:
-
# = Active Record
-
#
-
# Active Record objects don't specify their attributes directly, but rather infer them from
-
# the table definition with which they're linked. Adding, removing, and changing attributes
-
# and their type is done directly in the database. Any change is instantly reflected in the
-
# Active Record objects. The mapping that binds a given Active Record class to a certain
-
# database table will happen automatically in most common cases, but can be overwritten for the uncommon ones.
-
#
-
# See the mapping rules in table_name and the full example in link:files/activerecord/README_rdoc.html for more insight.
-
#
-
# == Creation
-
#
-
# Active Records accept constructor parameters either in a hash or as a block. The hash
-
# method is especially useful when you're receiving the data from somewhere else, like an
-
# HTTP request. It works like this:
-
#
-
# user = User.new(:name => "David", :occupation => "Code Artist")
-
# user.name # => "David"
-
#
-
# You can also use block initialization:
-
#
-
# user = User.new do |u|
-
# u.name = "David"
-
# u.occupation = "Code Artist"
-
# end
-
#
-
# And of course you can just create a bare object and specify the attributes after the fact:
-
#
-
# user = User.new
-
# user.name = "David"
-
# user.occupation = "Code Artist"
-
#
-
# == Conditions
-
#
-
# Conditions can either be specified as a string, array, or hash representing the WHERE-part of an SQL statement.
-
# The array form is to be used when the condition input is tainted and requires sanitization. The string form can
-
# be used for statements that don't involve tainted data. The hash form works much like the array form, except
-
# only equality and range is possible. Examples:
-
#
-
# class User < ActiveRecord::Base
-
# def self.authenticate_unsafely(user_name, password)
-
# where("user_name = '#{user_name}' AND password = '#{password}'").first
-
# end
-
#
-
# def self.authenticate_safely(user_name, password)
-
# where("user_name = ? AND password = ?", user_name, password).first
-
# end
-
#
-
# def self.authenticate_safely_simply(user_name, password)
-
# where(:user_name => user_name, :password => password).first
-
# end
-
# end
-
#
-
# The <tt>authenticate_unsafely</tt> method inserts the parameters directly into the query
-
# and is thus susceptible to SQL-injection attacks if the <tt>user_name</tt> and +password+
-
# parameters come directly from an HTTP request. The <tt>authenticate_safely</tt> and
-
# <tt>authenticate_safely_simply</tt> both will sanitize the <tt>user_name</tt> and +password+
-
# before inserting them in the query, which will ensure that an attacker can't escape the
-
# query and fake the login (or worse).
-
#
-
# When using multiple parameters in the conditions, it can easily become hard to read exactly
-
# what the fourth or fifth question mark is supposed to represent. In those cases, you can
-
# resort to named bind variables instead. That's done by replacing the question marks with
-
# symbols and supplying a hash with values for the matching symbol keys:
-
#
-
# Company.where(
-
# "id = :id AND name = :name AND division = :division AND created_at > :accounting_date",
-
# { :id => 3, :name => "37signals", :division => "First", :accounting_date => '2005-01-01' }
-
# ).first
-
#
-
# Similarly, a simple hash without a statement will generate conditions based on equality with the SQL AND
-
# operator. For instance:
-
#
-
# Student.where(:first_name => "Harvey", :status => 1)
-
# Student.where(params[:student])
-
#
-
# A range may be used in the hash to use the SQL BETWEEN operator:
-
#
-
# Student.where(:grade => 9..12)
-
#
-
# An array may be used in the hash to use the SQL IN operator:
-
#
-
# Student.where(:grade => [9,11,12])
-
#
-
# When joining tables, nested hashes or keys written in the form 'table_name.column_name'
-
# can be used to qualify the table name of a particular condition. For instance:
-
#
-
# Student.joins(:schools).where(:schools => { :category => 'public' })
-
# Student.joins(:schools).where('schools.category' => 'public' )
-
#
-
# == Overwriting default accessors
-
#
-
# All column values are automatically available through basic accessors on the Active Record
-
# object, but sometimes you want to specialize this behavior. This can be done by overwriting
-
# the default accessors (using the same name as the attribute) and calling
-
# <tt>read_attribute(attr_name)</tt> and <tt>write_attribute(attr_name, value)</tt> to actually
-
# change things.
-
#
-
# class Song < ActiveRecord::Base
-
# # Uses an integer of seconds to hold the length of the song
-
#
-
# def length=(minutes)
-
# write_attribute(:length, minutes.to_i * 60)
-
# end
-
#
-
# def length
-
# read_attribute(:length) / 60
-
# end
-
# end
-
#
-
# You can alternatively use <tt>self[:attribute]=(value)</tt> and <tt>self[:attribute]</tt>
-
# instead of <tt>write_attribute(:attribute, value)</tt> and <tt>read_attribute(:attribute)</tt>.
-
#
-
# == Attribute query methods
-
#
-
# In addition to the basic accessors, query methods are also automatically available on the Active Record object.
-
# Query methods allow you to test whether an attribute value is present.
-
#
-
# For example, an Active Record User with the <tt>name</tt> attribute has a <tt>name?</tt> method that you can call
-
# to determine whether the user has a name:
-
#
-
# user = User.new(:name => "David")
-
# user.name? # => true
-
#
-
# anonymous = User.new(:name => "")
-
# anonymous.name? # => false
-
#
-
# == Accessing attributes before they have been typecasted
-
#
-
# Sometimes you want to be able to read the raw attribute data without having the column-determined
-
# typecast run its course first. That can be done by using the <tt><attribute>_before_type_cast</tt>
-
# accessors that all attributes have. For example, if your Account model has a <tt>balance</tt> attribute,
-
# you can call <tt>account.balance_before_type_cast</tt> or <tt>account.id_before_type_cast</tt>.
-
#
-
# This is especially useful in validation situations where the user might supply a string for an
-
# integer field and you want to display the original string back in an error message. Accessing the
-
# attribute normally would typecast the string to 0, which isn't what you want.
-
#
-
# == Dynamic attribute-based finders
-
#
-
# Dynamic attribute-based finders are a cleaner way of getting (and/or creating) objects
-
# by simple queries without turning to SQL. They work by appending the name of an attribute
-
# to <tt>find_by_</tt>, <tt>find_last_by_</tt>, or <tt>find_all_by_</tt> and thus produces finders
-
# like <tt>Person.find_by_user_name</tt>, <tt>Person.find_all_by_last_name</tt>, and
-
# <tt>Payment.find_by_transaction_id</tt>. Instead of writing
-
# <tt>Person.where(:user_name => user_name).first</tt>, you just do <tt>Person.find_by_user_name(user_name)</tt>.
-
# And instead of writing <tt>Person.where(:last_name => last_name).all</tt>, you just do
-
# <tt>Person.find_all_by_last_name(last_name)</tt>.
-
#
-
# It's possible to add an exclamation point (!) on the end of the dynamic finders to get them to raise an
-
# <tt>ActiveRecord::RecordNotFound</tt> error if they do not return any records,
-
# like <tt>Person.find_by_last_name!</tt>.
-
#
-
# It's also possible to use multiple attributes in the same find by separating them with "_and_".
-
#
-
# Person.where(:user_name => user_name, :password => password).first
-
# Person.find_by_user_name_and_password(user_name, password) # with dynamic finder
-
#
-
# It's even possible to call these dynamic finder methods on relations and named scopes.
-
#
-
# Payment.order("created_on").find_all_by_amount(50)
-
# Payment.pending.find_last_by_amount(100)
-
#
-
# The same dynamic finder style can be used to create the object if it doesn't already exist.
-
# This dynamic finder is called with <tt>find_or_create_by_</tt> and will return the object if
-
# it already exists and otherwise creates it, then returns it. Protected attributes won't be set
-
# unless they are given in a block.
-
#
-
# # No 'Summer' tag exists
-
# Tag.find_or_create_by_name("Summer") # equal to Tag.create(:name => "Summer")
-
#
-
# # Now the 'Summer' tag does exist
-
# Tag.find_or_create_by_name("Summer") # equal to Tag.find_by_name("Summer")
-
#
-
# # Now 'Bob' exist and is an 'admin'
-
# User.find_or_create_by_name('Bob', :age => 40) { |u| u.admin = true }
-
#
-
# Adding an exclamation point (!) on to the end of <tt>find_or_create_by_</tt> will
-
# raise an <tt>ActiveRecord::RecordInvalid</tt> error if the new record is invalid.
-
#
-
# Use the <tt>find_or_initialize_by_</tt> finder if you want to return a new record without
-
# saving it first. Protected attributes won't be set unless they are given in a block.
-
#
-
# # No 'Winter' tag exists
-
# winter = Tag.find_or_initialize_by_name("Winter")
-
# winter.persisted? # false
-
#
-
# To find by a subset of the attributes to be used for instantiating a new object, pass a hash instead of
-
# a list of parameters.
-
#
-
# Tag.find_or_create_by_name(:name => "rails", :creator => current_user)
-
#
-
# That will either find an existing tag named "rails", or create a new one while setting the
-
# user that created it.
-
#
-
# Just like <tt>find_by_*</tt>, you can also use <tt>scoped_by_*</tt> to retrieve data. The good thing about
-
# using this feature is that the very first time result is returned using <tt>method_missing</tt> technique
-
# but after that the method is declared on the class. Henceforth <tt>method_missing</tt> will not be hit.
-
#
-
# User.scoped_by_user_name('David')
-
#
-
# == Saving arrays, hashes, and other non-mappable objects in text columns
-
#
-
# Active Record can serialize any object in text columns using YAML. To do so, you must
-
# specify this with a call to the class method +serialize+.
-
# This makes it possible to store arrays, hashes, and other non-mappable objects without doing
-
# any additional work.
-
#
-
# class User < ActiveRecord::Base
-
# serialize :preferences
-
# end
-
#
-
# user = User.create(:preferences => { "background" => "black", "display" => large })
-
# User.find(user.id).preferences # => { "background" => "black", "display" => large }
-
#
-
# You can also specify a class option as the second parameter that'll raise an exception
-
# if a serialized object is retrieved as a descendant of a class not in the hierarchy.
-
#
-
# class User < ActiveRecord::Base
-
# serialize :preferences, Hash
-
# end
-
#
-
# user = User.create(:preferences => %w( one two three ))
-
# User.find(user.id).preferences # raises SerializationTypeMismatch
-
#
-
# When you specify a class option, the default value for that attribute will be a new
-
# instance of that class.
-
#
-
# class User < ActiveRecord::Base
-
# serialize :preferences, OpenStruct
-
# end
-
#
-
# user = User.new
-
# user.preferences.theme_color = "red"
-
#
-
#
-
# == Single table inheritance
-
#
-
# Active Record allows inheritance by storing the name of the class in a column that by
-
# default is named "type" (can be changed by overwriting <tt>Base.inheritance_column</tt>).
-
# This means that an inheritance looking like this:
-
#
-
# class Company < ActiveRecord::Base; end
-
# class Firm < Company; end
-
# class Client < Company; end
-
# class PriorityClient < Client; end
-
#
-
# When you do <tt>Firm.create(:name => "37signals")</tt>, this record will be saved in
-
# the companies table with type = "Firm". You can then fetch this row again using
-
# <tt>Company.where(:name => '37signals').first</tt> and it will return a Firm object.
-
#
-
# If you don't have a type column defined in your table, single-table inheritance won't
-
# be triggered. In that case, it'll work just like normal subclasses with no special magic
-
# for differentiating between them or reloading the right type with find.
-
#
-
# Note, all the attributes for all the cases are kept in the same table. Read more:
-
# http://www.martinfowler.com/eaaCatalog/singleTableInheritance.html
-
#
-
# == Connection to multiple databases in different models
-
#
-
# Connections are usually created through ActiveRecord::Base.establish_connection and retrieved
-
# by ActiveRecord::Base.connection. All classes inheriting from ActiveRecord::Base will use this
-
# connection. But you can also set a class-specific connection. For example, if Course is an
-
# ActiveRecord::Base, but resides in a different database, you can just say <tt>Course.establish_connection</tt>
-
# and Course and all of its subclasses will use this connection instead.
-
#
-
# This feature is implemented by keeping a connection pool in ActiveRecord::Base that is
-
# a Hash indexed by the class. If a connection is requested, the retrieve_connection method
-
# will go up the class-hierarchy until a connection is found in the connection pool.
-
#
-
# == Exceptions
-
#
-
# * ActiveRecordError - Generic error class and superclass of all other errors raised by Active Record.
-
# * AdapterNotSpecified - The configuration hash used in <tt>establish_connection</tt> didn't include an
-
# <tt>:adapter</tt> key.
-
# * AdapterNotFound - The <tt>:adapter</tt> key used in <tt>establish_connection</tt> specified a
-
# non-existent adapter
-
# (or a bad spelling of an existing one).
-
# * AssociationTypeMismatch - The object assigned to the association wasn't of the type
-
# specified in the association definition.
-
# * AttributeAssignmentError - An error occurred while doing a mass assignment through the
-
# <tt>attributes=</tt> method.
-
# You can inspect the +attribute+ property of the exception object to determine which attribute
-
# triggered the error.
-
# * ConnectionNotEstablished - No connection has been established. Use <tt>establish_connection</tt>
-
# before querying.
-
# * MultiparameterAssignmentErrors - Collection of errors that occurred during a mass assignment using the
-
# <tt>attributes=</tt> method. The +errors+ property of this exception contains an array of
-
# AttributeAssignmentError
-
# objects that should be inspected to determine which attributes triggered the errors.
-
# * RecordInvalid - raised by save! and create! when the record is invalid.
-
# * RecordNotFound - No record responded to the +find+ method. Either the row with the given ID doesn't exist
-
# or the row didn't meet the additional restrictions. Some +find+ calls do not raise this exception to signal
-
# nothing was found, please check its documentation for further details.
-
# * SerializationTypeMismatch - The serialized object wasn't of the class specified as the second parameter.
-
# * StatementInvalid - The database server rejected the SQL statement. The precise error is added in the message.
-
#
-
# *Note*: The attributes listed are class-level attributes (accessible from both the class and instance level).
-
# So it's possible to assign a logger to the class through <tt>Base.logger=</tt> which will then be used by all
-
# instances in the current object space.
-
1
class Base
-
1
extend ActiveModel::Observing::ClassMethods
-
1
extend ActiveModel::Naming
-
-
1
extend ActiveSupport::Benchmarkable
-
1
extend ActiveSupport::DescendantsTracker
-
-
1
extend ConnectionHandling
-
1
extend QueryCache::ClassMethods
-
1
extend Querying
-
1
extend Translation
-
1
extend DynamicMatchers
-
1
extend Explain
-
-
1
include Persistence
-
1
include ReadonlyAttributes
-
1
include ModelSchema
-
1
include Inheritance
-
1
include Scoping
-
1
include Sanitization
-
1
include AttributeAssignment
-
1
include ActiveModel::Conversion
-
1
include Integration
-
1
include Validations
-
1
include CounterCache
-
1
include Locking::Optimistic
-
1
include Locking::Pessimistic
-
1
include AttributeMethods
-
1
include Callbacks
-
1
include ActiveModel::Observing
-
1
include Timestamp
-
1
include Associations
-
1
include ActiveModel::SecurePassword
-
1
include AutosaveAssociation
-
1
include NestedAttributes
-
1
include Aggregations
-
1
include Transactions
-
1
include Reflection
-
1
include Serialization
-
1
include Store
-
1
include Core
-
end
-
-
1
ActiveSupport.run_load_hooks(:active_record, Base)
-
end
-
1
module ActiveRecord
-
# = Active Record Callbacks
-
#
-
# Callbacks are hooks into the life cycle of an Active Record object that allow you to trigger logic
-
# before or after an alteration of the object state. This can be used to make sure that associated and
-
# dependent objects are deleted when +destroy+ is called (by overwriting +before_destroy+) or to massage attributes
-
# before they're validated (by overwriting +before_validation+). As an example of the callbacks initiated, consider
-
# the <tt>Base#save</tt> call for a new record:
-
#
-
# * (-) <tt>save</tt>
-
# * (-) <tt>valid</tt>
-
# * (1) <tt>before_validation</tt>
-
# * (-) <tt>validate</tt>
-
# * (2) <tt>after_validation</tt>
-
# * (3) <tt>before_save</tt>
-
# * (4) <tt>before_create</tt>
-
# * (-) <tt>create</tt>
-
# * (5) <tt>after_create</tt>
-
# * (6) <tt>after_save</tt>
-
# * (7) <tt>after_commit</tt>
-
#
-
# Also, an <tt>after_rollback</tt> callback can be configured to be triggered whenever a rollback is issued.
-
# Check out <tt>ActiveRecord::Transactions</tt> for more details about <tt>after_commit</tt> and
-
# <tt>after_rollback</tt>.
-
#
-
# Lastly an <tt>after_find</tt> and <tt>after_initialize</tt> callback is triggered for each object that
-
# is found and instantiated by a finder, with <tt>after_initialize</tt> being triggered after new objects
-
# are instantiated as well.
-
#
-
# That's a total of twelve callbacks, which gives you immense power to react and prepare for each state in the
-
# Active Record life cycle. The sequence for calling <tt>Base#save</tt> for an existing record is similar,
-
# except that each <tt>_create</tt> callback is replaced by the corresponding <tt>_update</tt> callback.
-
#
-
# Examples:
-
# class CreditCard < ActiveRecord::Base
-
# # Strip everything but digits, so the user can specify "555 234 34" or
-
# # "5552-3434" and both will mean "55523434"
-
# before_validation(:on => :create) do
-
# self.number = number.gsub(/[^0-9]/, "") if attribute_present?("number")
-
# end
-
# end
-
#
-
# class Subscription < ActiveRecord::Base
-
# before_create :record_signup
-
#
-
# private
-
# def record_signup
-
# self.signed_up_on = Date.today
-
# end
-
# end
-
#
-
# class Firm < ActiveRecord::Base
-
# # Destroys the associated clients and people when the firm is destroyed
-
# before_destroy { |record| Person.destroy_all "firm_id = #{record.id}" }
-
# before_destroy { |record| Client.destroy_all "client_of = #{record.id}" }
-
# end
-
#
-
# == Inheritable callback queues
-
#
-
# Besides the overwritable callback methods, it's also possible to register callbacks through the
-
# use of the callback macros. Their main advantage is that the macros add behavior into a callback
-
# queue that is kept intact down through an inheritance hierarchy.
-
#
-
# class Topic < ActiveRecord::Base
-
# before_destroy :destroy_author
-
# end
-
#
-
# class Reply < Topic
-
# before_destroy :destroy_readers
-
# end
-
#
-
# Now, when <tt>Topic#destroy</tt> is run only +destroy_author+ is called. When <tt>Reply#destroy</tt> is
-
# run, both +destroy_author+ and +destroy_readers+ are called. Contrast this to the following situation
-
# where the +before_destroy+ method is overridden:
-
#
-
# class Topic < ActiveRecord::Base
-
# def before_destroy() destroy_author end
-
# end
-
#
-
# class Reply < Topic
-
# def before_destroy() destroy_readers end
-
# end
-
#
-
# In that case, <tt>Reply#destroy</tt> would only run +destroy_readers+ and _not_ +destroy_author+.
-
# So, use the callback macros when you want to ensure that a certain callback is called for the entire
-
# hierarchy, and use the regular overwriteable methods when you want to leave it up to each descendant
-
# to decide whether they want to call +super+ and trigger the inherited callbacks.
-
#
-
# *IMPORTANT:* In order for inheritance to work for the callback queues, you must specify the
-
# callbacks before specifying the associations. Otherwise, you might trigger the loading of a
-
# child before the parent has registered the callbacks and they won't be inherited.
-
#
-
# == Types of callbacks
-
#
-
# There are four types of callbacks accepted by the callback macros: Method references (symbol), callback objects,
-
# inline methods (using a proc), and inline eval methods (using a string). Method references and callback objects
-
# are the recommended approaches, inline methods using a proc are sometimes appropriate (such as for
-
# creating mix-ins), and inline eval methods are deprecated.
-
#
-
# The method reference callbacks work by specifying a protected or private method available in the object, like this:
-
#
-
# class Topic < ActiveRecord::Base
-
# before_destroy :delete_parents
-
#
-
# private
-
# def delete_parents
-
# self.class.delete_all "parent_id = #{id}"
-
# end
-
# end
-
#
-
# The callback objects have methods named after the callback called with the record as the only parameter, such as:
-
#
-
# class BankAccount < ActiveRecord::Base
-
# before_save EncryptionWrapper.new
-
# after_save EncryptionWrapper.new
-
# after_initialize EncryptionWrapper.new
-
# end
-
#
-
# class EncryptionWrapper
-
# def before_save(record)
-
# record.credit_card_number = encrypt(record.credit_card_number)
-
# end
-
#
-
# def after_save(record)
-
# record.credit_card_number = decrypt(record.credit_card_number)
-
# end
-
#
-
# alias_method :after_find, :after_save
-
#
-
# private
-
# def encrypt(value)
-
# # Secrecy is committed
-
# end
-
#
-
# def decrypt(value)
-
# # Secrecy is unveiled
-
# end
-
# end
-
#
-
# So you specify the object you want messaged on a given callback. When that callback is triggered, the object has
-
# a method by the name of the callback messaged. You can make these callbacks more flexible by passing in other
-
# initialization data such as the name of the attribute to work with:
-
#
-
# class BankAccount < ActiveRecord::Base
-
# before_save EncryptionWrapper.new("credit_card_number")
-
# after_save EncryptionWrapper.new("credit_card_number")
-
# after_initialize EncryptionWrapper.new("credit_card_number")
-
# end
-
#
-
# class EncryptionWrapper
-
# def initialize(attribute)
-
# @attribute = attribute
-
# end
-
#
-
# def before_save(record)
-
# record.send("#{@attribute}=", encrypt(record.send("#{@attribute}")))
-
# end
-
#
-
# def after_save(record)
-
# record.send("#{@attribute}=", decrypt(record.send("#{@attribute}")))
-
# end
-
#
-
# alias_method :after_find, :after_save
-
#
-
# private
-
# def encrypt(value)
-
# # Secrecy is committed
-
# end
-
#
-
# def decrypt(value)
-
# # Secrecy is unveiled
-
# end
-
# end
-
#
-
# The callback macros usually accept a symbol for the method they're supposed to run, but you can also
-
# pass a "method string", which will then be evaluated within the binding of the callback. Example:
-
#
-
# class Topic < ActiveRecord::Base
-
# before_destroy 'self.class.delete_all "parent_id = #{id}"'
-
# end
-
#
-
# Notice that single quotes (') are used so the <tt>#{id}</tt> part isn't evaluated until the callback
-
# is triggered. Also note that these inline callbacks can be stacked just like the regular ones:
-
#
-
# class Topic < ActiveRecord::Base
-
# before_destroy 'self.class.delete_all "parent_id = #{id}"',
-
# 'puts "Evaluated after parents are destroyed"'
-
# end
-
#
-
# == <tt>before_validation*</tt> returning statements
-
#
-
# If the returning value of a +before_validation+ callback can be evaluated to +false+, the process will be
-
# aborted and <tt>Base#save</tt> will return +false+. If Base#save! is called it will raise a
-
# ActiveRecord::RecordInvalid exception. Nothing will be appended to the errors object.
-
#
-
# == Canceling callbacks
-
#
-
# If a <tt>before_*</tt> callback returns +false+, all the later callbacks and the associated action are
-
# cancelled. If an <tt>after_*</tt> callback returns +false+, all the later callbacks are cancelled.
-
# Callbacks are generally run in the order they are defined, with the exception of callbacks defined as
-
# methods on the model, which are called last.
-
#
-
# == Ordering callbacks
-
#
-
# Sometimes the code needs that the callbacks execute in a specific order. For example, a +before_destroy+
-
# callback (+log_children+ in this case) should be executed before the children get destroyed by the +dependent: destroy+ option.
-
#
-
# Let's look at the code below:
-
#
-
# class Topic < ActiveRecord::Base
-
# has_many :children, dependent: destroy
-
#
-
# before_destroy :log_children
-
#
-
# private
-
# def log_children
-
# # Child processing
-
# end
-
# end
-
#
-
# In this case, the problem is that when the +before_destroy+ callback is executed, the children are not available
-
# because the +destroy+ callback gets executed first. You can use the +prepend+ option on the +before_destroy+ callback to avoid this.
-
#
-
# class Topic < ActiveRecord::Base
-
# has_many :children, dependent: destroy
-
#
-
# before_destroy :log_children, prepend: true
-
#
-
# private
-
# def log_children
-
# # Child processing
-
# end
-
# end
-
#
-
# This way, the +before_destroy+ gets executed before the <tt>dependent: destroy</tt> is called, and the data is still available.
-
#
-
# == Transactions
-
#
-
# The entire callback chain of a +save+, <tt>save!</tt>, or +destroy+ call runs
-
# within a transaction. That includes <tt>after_*</tt> hooks. If everything
-
# goes fine a COMMIT is executed once the chain has been completed.
-
#
-
# If a <tt>before_*</tt> callback cancels the action a ROLLBACK is issued. You
-
# can also trigger a ROLLBACK raising an exception in any of the callbacks,
-
# including <tt>after_*</tt> hooks. Note, however, that in that case the client
-
# needs to be aware of it because an ordinary +save+ will raise such exception
-
# instead of quietly returning +false+.
-
#
-
# == Debugging callbacks
-
#
-
# The callback chain is accessible via the <tt>_*_callbacks</tt> method on an object. ActiveModel Callbacks support
-
# <tt>:before</tt>, <tt>:after</tt> and <tt>:around</tt> as values for the <tt>kind</tt> property. The <tt>kind</tt> property
-
# defines what part of the chain the callback runs in.
-
#
-
# To find all callbacks in the before_save callback chain:
-
#
-
# Topic._save_callbacks.select { |cb| cb.kind.eql?(:before) }
-
#
-
# Returns an array of callback objects that form the before_save chain.
-
#
-
# To further check if the before_save chain contains a proc defined as <tt>rest_when_dead</tt> use the <tt>filter</tt> property of the callback object:
-
#
-
# Topic._save_callbacks.select { |cb| cb.kind.eql?(:before) }.collect(&:filter).include?(:rest_when_dead)
-
#
-
# Returns true or false depending on whether the proc is contained in the before_save callback chain on a Topic model.
-
#
-
1
module Callbacks
-
1
extend ActiveSupport::Concern
-
-
1
CALLBACKS = [
-
:after_initialize, :after_find, :after_touch, :before_validation, :after_validation,
-
:before_save, :around_save, :after_save, :before_create, :around_create,
-
:after_create, :before_update, :around_update, :after_update,
-
:before_destroy, :around_destroy, :after_destroy, :after_commit, :after_rollback
-
]
-
-
1
module ClassMethods
-
1
include ActiveModel::Callbacks
-
end
-
-
1
included do
-
1
include ActiveModel::Validations::Callbacks
-
-
1
define_model_callbacks :initialize, :find, :touch, :only => :after
-
1
define_model_callbacks :save, :create, :update, :destroy
-
end
-
-
1
def destroy #:nodoc:
-
478
run_callbacks(:destroy) { super }
-
end
-
-
1
def touch(*) #:nodoc:
-
56
run_callbacks(:touch) { super }
-
end
-
-
1
private
-
-
1
def create_or_update #:nodoc:
-
5923
run_callbacks(:save) { super }
-
end
-
-
1
def create #:nodoc:
-
4642
run_callbacks(:create) { super }
-
end
-
-
1
def update(*) #:nodoc:
-
1224
run_callbacks(:update) { super }
-
end
-
end
-
end
-
1
require 'yaml'
-
-
1
module ActiveRecord
-
1
module Coders # :nodoc:
-
1
class YAMLColumn # :nodoc:
-
1
RESCUE_ERRORS = [ ArgumentError, Psych::SyntaxError ]
-
-
1
attr_accessor :object_class
-
-
1
def initialize(object_class = Object)
-
47
@object_class = object_class
-
end
-
-
1
def dump(obj)
-
315
return if obj.nil?
-
-
213
unless obj.is_a?(object_class)
-
2
raise SerializationTypeMismatch,
-
"Attribute was supposed to be a #{object_class}, but was a #{obj.class}. -- #{obj.inspect}"
-
end
-
211
YAML.dump obj
-
end
-
-
1
def load(yaml)
-
558
return object_class.new if object_class != Object && yaml.nil?
-
548
return yaml unless yaml.is_a?(String) && yaml =~ /^---/
-
160
begin
-
160
obj = YAML.load(yaml)
-
-
159
unless obj.is_a?(object_class) || obj.nil?
-
2
raise SerializationTypeMismatch,
-
"Attribute was supposed to be a #{object_class}, but was a #{obj.class}"
-
end
-
157
obj ||= object_class.new if object_class != Object
-
-
157
obj
-
3
rescue *RESCUE_ERRORS
-
1
yaml
-
end
-
end
-
end
-
end
-
end
-
1
require 'thread'
-
1
require 'monitor'
-
1
require 'set'
-
1
require 'active_support/deprecation'
-
-
1
module ActiveRecord
-
# Raised when a connection could not be obtained within the connection
-
# acquisition timeout period: because max connections in pool
-
# are in use.
-
1
class ConnectionTimeoutError < ConnectionNotEstablished
-
end
-
-
1
module ConnectionAdapters
-
# Connection pool base class for managing Active Record database
-
# connections.
-
#
-
# == Introduction
-
#
-
# A connection pool synchronizes thread access to a limited number of
-
# database connections. The basic idea is that each thread checks out a
-
# database connection from the pool, uses that connection, and checks the
-
# connection back in. ConnectionPool is completely thread-safe, and will
-
# ensure that a connection cannot be used by two threads at the same time,
-
# as long as ConnectionPool's contract is correctly followed. It will also
-
# handle cases in which there are more threads than connections: if all
-
# connections have been checked out, and a thread tries to checkout a
-
# connection anyway, then ConnectionPool will wait until some other thread
-
# has checked in a connection.
-
#
-
# == Obtaining (checking out) a connection
-
#
-
# Connections can be obtained and used from a connection pool in several
-
# ways:
-
#
-
# 1. Simply use ActiveRecord::Base.connection as with Active Record 2.1 and
-
# earlier (pre-connection-pooling). Eventually, when you're done with
-
# the connection(s) and wish it to be returned to the pool, you call
-
# ActiveRecord::Base.clear_active_connections!. This will be the
-
# default behavior for Active Record when used in conjunction with
-
# Action Pack's request handling cycle.
-
# 2. Manually check out a connection from the pool with
-
# ActiveRecord::Base.connection_pool.checkout. You are responsible for
-
# returning this connection to the pool when finished by calling
-
# ActiveRecord::Base.connection_pool.checkin(connection).
-
# 3. Use ActiveRecord::Base.connection_pool.with_connection(&block), which
-
# obtains a connection, yields it as the sole argument to the block,
-
# and returns it to the pool after the block completes.
-
#
-
# Connections in the pool are actually AbstractAdapter objects (or objects
-
# compatible with AbstractAdapter's interface).
-
#
-
# == Options
-
#
-
# There are several connection-pooling-related options that you can add to
-
# your database connection configuration:
-
#
-
# * +pool+: number indicating size of connection pool (default 5)
-
# * +checkout_timeout+: number of seconds to block and wait for a connection
-
# before giving up and raising a timeout error (default 5 seconds).
-
# * +reaping_frequency+: frequency in seconds to periodically run the
-
# Reaper, which attempts to find and close dead connections, which can
-
# occur if a programmer forgets to close a connection at the end of a
-
# thread or a thread dies unexpectedly. (Default nil, which means don't
-
# run the Reaper).
-
# * +dead_connection_timeout+: number of seconds from last checkout
-
# after which the Reaper will consider a connection reapable. (default
-
# 5 seconds).
-
1
class ConnectionPool
-
# Threadsafe, fair, FIFO queue. Meant to be used by ConnectionPool
-
# with which it shares a Monitor. But could be a generic Queue.
-
#
-
# The Queue in stdlib's 'thread' could replace this class except
-
# stdlib's doesn't support waiting with a timeout.
-
1
class Queue
-
1
def initialize(lock = Monitor.new)
-
60
@lock = lock
-
60
@cond = @lock.new_cond
-
60
@num_waiting = 0
-
60
@queue = []
-
end
-
-
# Test if any threads are currently waiting on the queue.
-
1
def any_waiting?
-
7
synchronize do
-
7
@num_waiting > 0
-
end
-
end
-
-
# Return the number of threads currently waiting on this
-
# queue.
-
1
def num_waiting
-
synchronize do
-
@num_waiting
-
end
-
end
-
-
# Add +element+ to the queue. Never blocks.
-
1
def add(element)
-
16843
synchronize do
-
16843
@queue.push element
-
16843
@cond.signal
-
end
-
end
-
-
# If +element+ is in the queue, remove and return it, or nil.
-
1
def delete(element)
-
7
synchronize do
-
7
@queue.delete(element)
-
end
-
end
-
-
# Remove all elements from the queue.
-
1
def clear
-
47
synchronize do
-
47
@queue.clear
-
end
-
end
-
-
# Remove the head of the queue.
-
#
-
# If +timeout+ is not given, remove and return the head the
-
# queue if the number of available elements is strictly
-
# greater than the number of threads currently waiting (that
-
# is, don't jump ahead in line). Otherwise, return nil.
-
#
-
# If +timeout+ is given, block if it there is no element
-
# available, waiting up to +timeout+ seconds for an element to
-
# become available.
-
#
-
# Raises:
-
# - ConnectionTimeoutError if +timeout+ is given and no element
-
# becomes available after +timeout+ seconds,
-
1
def poll(timeout = nil)
-
16833
synchronize do
-
16833
if timeout
-
23
no_wait_poll || wait_poll(timeout)
-
else
-
16810
no_wait_poll
-
end
-
end
-
end
-
-
1
private
-
-
1
def synchronize(&block)
-
33737
@lock.synchronize(&block)
-
end
-
-
# Test if the queue currently contains any elements.
-
1
def any?
-
23
!@queue.empty?
-
end
-
-
# A thread can remove an element from the queue without
-
# waiting if an only if the number of currently available
-
# connections is strictly greater than the number of waiting
-
# threads.
-
1
def can_remove_no_wait?
-
16833
@queue.size > @num_waiting
-
end
-
-
# Removes and returns the head of the queue if possible, or nil.
-
1
def remove
-
16713
@queue.shift
-
end
-
-
# Remove and return the head the queue if the number of
-
# available elements is strictly greater than the number of
-
# threads currently waiting. Otherwise, return nil.
-
1
def no_wait_poll
-
16833
remove if can_remove_no_wait?
-
end
-
-
# Waits on the queue up to +timeout+ seconds, then removes and
-
# returns the head of the queue.
-
1
def wait_poll(timeout)
-
23
@num_waiting += 1
-
-
23
t0 = Time.now
-
23
elapsed = 0
-
23
loop do
-
23
@cond.wait(timeout - elapsed)
-
-
23
return remove if any?
-
-
1
elapsed = Time.now - t0
-
1
if elapsed >= timeout
-
1
msg = 'could not obtain a database connection within %0.3f seconds (waited %0.3f seconds)' %
-
[timeout, elapsed]
-
1
raise ConnectionTimeoutError, msg
-
end
-
end
-
ensure
-
23
@num_waiting -= 1
-
end
-
end
-
-
# Every +frequency+ seconds, the reaper will call +reap+ on +pool+.
-
# A reaper instantiated with a nil frequency will never reap the
-
# connection pool.
-
#
-
# Configure the frequency by setting "reaping_frequency" in your
-
# database yaml file.
-
1
class Reaper
-
1
attr_reader :pool, :frequency
-
-
1
def initialize(pool, frequency)
-
62
@pool = pool
-
62
@frequency = frequency
-
end
-
-
1
def run
-
62
return unless frequency
-
3
Thread.new(frequency, pool) { |t, p|
-
3
while true
-
298821
sleep t
-
298819
p.reap
-
end
-
}
-
end
-
end
-
-
1
include MonitorMixin
-
-
1
attr_accessor :automatic_reconnect, :checkout_timeout, :dead_connection_timeout
-
1
attr_reader :spec, :connections, :size, :reaper
-
-
# Creates a new ConnectionPool object. +spec+ is a ConnectionSpecification
-
# object which describes database connection information (e.g. adapter,
-
# host name, username, password, etc), as well as the maximum size for
-
# this ConnectionPool.
-
#
-
# The default ConnectionPool maximum size is 5.
-
1
def initialize(spec)
-
60
super()
-
-
60
@spec = spec
-
-
# The cache of reserved connections mapped to threads
-
60
@reserved_connections = {}
-
-
60
@checkout_timeout = spec.config[:checkout_timeout] || 5
-
60
@dead_connection_timeout = spec.config[:dead_connection_timeout]
-
60
@reaper = Reaper.new self, spec.config[:reaping_frequency]
-
60
@reaper.run
-
-
# default max pool size to 5
-
60
@size = (spec.config[:pool] && spec.config[:pool].to_i) || 5
-
-
60
@connections = []
-
60
@automatic_reconnect = true
-
-
60
@available = Queue.new self
-
end
-
-
# Hack for tests to be able to add connections. Do not call outside of tests
-
1
def insert_connection_for_test!(c) #:nodoc:
-
1
synchronize do
-
1
@connections << c
-
1
@available.add c
-
end
-
end
-
-
# Retrieve the connection associated with the current thread, or call
-
# #checkout to obtain one if necessary.
-
#
-
# #connection can be called any number of times; the connection is
-
# held in a hash keyed by the thread id.
-
1
def connection
-
59868
synchronize do
-
59868
@reserved_connections[current_connection_id] ||= checkout
-
end
-
end
-
-
# Is there an open connection that is being used for the current thread?
-
1
def active_connection?
-
111
synchronize do
-
111
@reserved_connections.fetch(current_connection_id) {
-
18
return false
-
}.in_use?
-
end
-
end
-
-
# Signal that the thread is finished with the current connection.
-
# #release_connection releases the connection-thread association
-
# and returns the connection to the pool.
-
1
def release_connection(with_id = current_connection_id)
-
17914
synchronize do
-
17914
conn = @reserved_connections.delete(with_id)
-
17914
checkin conn if conn
-
end
-
end
-
-
# If a connection already exists yield it to the block. If no connection
-
# exists checkout a connection, yield it to the block, and checkin the
-
# connection when finished.
-
1
def with_connection
-
80
connection_id = current_connection_id
-
80
fresh_connection = true unless active_connection?
-
80
yield connection
-
ensure
-
80
release_connection(connection_id) if fresh_connection
-
end
-
-
# Returns true if a connection has already been opened.
-
1
def connected?
-
350
synchronize { @connections.any? }
-
end
-
-
# Disconnects all connections in the pool, and clears the pool.
-
1
def disconnect!
-
42
synchronize do
-
42
@reserved_connections = {}
-
42
@connections.each do |conn|
-
74
checkin conn
-
74
conn.disconnect!
-
end
-
42
@connections = []
-
42
@available.clear
-
end
-
end
-
-
# Clears the cache which maps classes.
-
1
def clear_reloadable_connections!
-
5
synchronize do
-
5
@reserved_connections = {}
-
5
@connections.each do |conn|
-
13
checkin conn
-
13
conn.disconnect! if conn.requires_reloading?
-
end
-
5
@connections.delete_if do |conn|
-
13
conn.requires_reloading?
-
end
-
5
@available.clear
-
5
@connections.each do |conn|
-
13
@available.add conn
-
end
-
end
-
end
-
-
1
def clear_stale_cached_connections! # :nodoc:
-
reap
-
end
-
1
deprecate :clear_stale_cached_connections! => "Please use #reap instead"
-
-
# Check-out a database connection from the pool, indicating that you want
-
# to use it. You should call #checkin when you no longer need this.
-
#
-
# This is done by either returning and leasing existing connection, or by
-
# creating a new connection and leasing it.
-
#
-
# If all connections are leased and the pool is at capacity (meaning the
-
# number of currently leased connections is greater than or equal to the
-
# size limit set), an ActiveRecord::ConnectionTimeoutError exception will be raised.
-
#
-
# Returns: an AbstractAdapter object.
-
#
-
# Raises:
-
# - ConnectionTimeoutError: no connection can be obtained from the pool.
-
1
def checkout
-
16810
synchronize do
-
16810
conn = acquire_connection
-
16807
conn.lease
-
16807
checkout_and_verify(conn)
-
end
-
end
-
-
# Check-in a database connection back into the pool, indicating that you
-
# no longer need this connection.
-
#
-
# +conn+: an AbstractAdapter object, which was obtained by earlier by
-
# calling +checkout+ on this pool.
-
1
def checkin(conn)
-
16828
synchronize do
-
16828
conn.run_callbacks :checkin do
-
16828
conn.expire
-
end
-
-
16828
release conn
-
-
16828
@available.add conn
-
end
-
end
-
-
# Remove a connection from the connection pool. The connection will
-
# remain open and active but will no longer be managed by this pool.
-
1
def remove(conn)
-
7
synchronize do
-
7
@connections.delete conn
-
7
@available.delete conn
-
-
# FIXME: we might want to store the key on the connection so that removing
-
# from the reserved hash will be a little easier.
-
7
release conn
-
-
7
@available.add checkout_new_connection if @available.any_waiting?
-
end
-
end
-
-
# Removes dead connections from the pool. A dead connection can occur
-
# if a programmer forgets to close a connection at the end of a thread
-
# or a thread dies unexpectedly.
-
1
def reap
-
146161
synchronize do
-
146161
stale = Time.now - @dead_connection_timeout
-
146160
connections.dup.each do |conn|
-
7
remove conn if conn.in_use? && stale > conn.last_use && !conn.active?
-
end
-
end
-
end
-
-
1
private
-
-
# Acquire a connection by one of 1) immediately removing one
-
# from the queue of available connections, 2) creating a new
-
# connection if the pool is not at capacity, 3) waiting on the
-
# queue for a connection to become available.
-
#
-
# Raises:
-
# - ConnectionTimeoutError if a connection could not be acquired
-
1
def acquire_connection
-
16810
if conn = @available.poll
-
16691
conn
-
119
elsif @connections.size < @size
-
96
checkout_new_connection
-
else
-
23
@available.poll(@checkout_timeout)
-
end
-
end
-
-
1
def release(conn)
-
16835
thread_id = if @reserved_connections[current_connection_id] == conn
-
17
current_connection_id
-
else
-
16818
@reserved_connections.keys.find { |k|
-
4822
@reserved_connections[k] == conn
-
}
-
end
-
-
16835
@reserved_connections.delete thread_id if thread_id
-
end
-
-
1
def new_connection
-
95
Base.send(spec.adapter_method, spec.config)
-
end
-
-
1
def current_connection_id #:nodoc:
-
94821
Base.connection_id ||= Thread.current.object_id
-
end
-
-
1
def checkout_new_connection
-
97
raise ConnectionNotEstablished unless @automatic_reconnect
-
-
95
c = new_connection
-
95
c.pool = self
-
95
@connections << c
-
95
c
-
end
-
-
1
def checkout_and_verify(c)
-
16807
c.run_callbacks :checkout do
-
16807
c.verify!
-
end
-
16807
c
-
end
-
end
-
-
# ConnectionHandler is a collection of ConnectionPool objects. It is used
-
# for keeping separate connection pools for Active Record models that connect
-
# to different databases.
-
#
-
# For example, suppose that you have 5 models, with the following hierarchy:
-
#
-
# |
-
# +-- Book
-
# | |
-
# | +-- ScaryBook
-
# | +-- GoodBook
-
# +-- Author
-
# +-- BankAccount
-
#
-
# Suppose that Book is to connect to a separate database (i.e. one other
-
# than the default database). Then Book, ScaryBook and GoodBook will all use
-
# the same connection pool. Likewise, Author and BankAccount will use the
-
# same connection pool. However, the connection pool used by Author/BankAccount
-
# is not the same as the one used by Book/ScaryBook/GoodBook.
-
#
-
# Normally there is only a single ConnectionHandler instance, accessible via
-
# ActiveRecord::Base.connection_handler. Active Record models use this to
-
# determine the connection pool that they should use.
-
1
class ConnectionHandler
-
1
def initialize
-
16
@owner_to_pool = Hash.new { |h,k| h[k] = {} }
-
36
@class_to_pool = Hash.new { |h,k| h[k] = {} }
-
end
-
-
1
def connection_pool_list
-
6994
owner_to_pool.values.compact
-
end
-
-
1
def connection_pools
-
1
ActiveSupport::Deprecation.warn(
-
"In the next release, this will return the same as #connection_pool_list. " \
-
"(An array of pools, rather than a hash mapping specs to pools.)"
-
)
-
2
Hash[connection_pool_list.map { |pool| [pool.spec, pool] }]
-
end
-
-
1
def establish_connection(owner, spec)
-
33
@class_to_pool.clear
-
33
owner_to_pool[owner] = ConnectionAdapters::ConnectionPool.new(spec)
-
end
-
-
# Returns true if there are any active connections among the connection
-
# pools that the ConnectionHandler is managing.
-
1
def active_connections?
-
19
connection_pool_list.any?(&:active_connection?)
-
end
-
-
# Returns any connections in use by the current thread back to the pool,
-
# and also returns connections to the pool cached by threads that are no
-
# longer alive.
-
1
def clear_active_connections!
-
3638
connection_pool_list.each(&:release_connection)
-
end
-
-
# Clears the cache which maps classes.
-
1
def clear_reloadable_connections!
-
connection_pool_list.each(&:clear_reloadable_connections!)
-
end
-
-
1
def clear_all_connections!
-
1
connection_pool_list.each(&:disconnect!)
-
end
-
-
# Locate the connection of the nearest super class. This can be an
-
# active or defined connection: if it is the latter, it will be
-
# opened and set as the active connection for the class it was defined
-
# for (not necessarily the current class).
-
1
def retrieve_connection(klass) #:nodoc:
-
43381
pool = retrieve_connection_pool(klass)
-
43381
(pool && pool.connection) or raise ConnectionNotEstablished
-
end
-
-
# Returns true if a connection that's accessible to this class has
-
# already been opened.
-
1
def connected?(klass)
-
175
conn = retrieve_connection_pool(klass)
-
175
conn && conn.connected?
-
end
-
-
# Remove the connection for this class. This will close the active
-
# connection and the defined connection (if they exist). The result
-
# can be used as an argument for establish_connection, for easily
-
# re-establishing the connection.
-
1
def remove_connection(owner)
-
33
if pool = owner_to_pool.delete(owner)
-
18
@class_to_pool.clear
-
18
pool.automatic_reconnect = false
-
18
pool.disconnect!
-
18
pool.spec.config
-
end
-
end
-
-
# Retrieving the connection pool happens a lot so we cache it in @class_to_pool.
-
# This makes retrieving the connection pool O(1) once the process is warm.
-
# When a connection is established or removed, we invalidate the cache.
-
#
-
# Ideally we would use #fetch here, as class_to_pool[klass] may sometimes be nil.
-
# However, benchmarking (https://gist.github.com/3552829) showed that #fetch is
-
# significantly slower than #[]. So in the nil case, no caching will take place,
-
# but that's ok since the nil case is not the common one that we wish to optimise
-
# for.
-
1
def retrieve_connection_pool(klass)
-
44163
class_to_pool[klass] ||= begin
-
687
until pool = pool_for(klass)
-
821
klass = klass.superclass
-
821
break unless klass <= Base
-
end
-
-
687
class_to_pool[klass] = pool
-
end
-
end
-
-
1
private
-
-
1
def owner_to_pool
-
8994
@owner_to_pool[Process.pid]
-
end
-
-
1
def class_to_pool
-
44850
@class_to_pool[Process.pid]
-
end
-
-
1
def pool_for(owner)
-
1504
owner_to_pool.fetch(owner) {
-
430
if ancestor_pool = pool_from_any_process_for(owner)
-
# A connection was established in an ancestor process that must have
-
# subsequently forked. We can't reuse the connection, but we can copy
-
# the specification and establish a new connection with it.
-
establish_connection owner, ancestor_pool.spec
-
else
-
430
owner_to_pool[owner] = nil
-
end
-
}
-
end
-
-
1
def pool_from_any_process_for(owner)
-
860
owner_to_pool = @owner_to_pool.values.find { |v| v[owner] }
-
430
owner_to_pool && owner_to_pool[owner]
-
end
-
end
-
-
1
class ConnectionManagement
-
1
def initialize(app)
-
14
@app = app
-
end
-
-
1
def call(env)
-
9
testing = env.key?('rack.test')
-
-
9
response = @app.call(env)
-
7
response[2] = ::Rack::BodyProxy.new(response[2]) do
-
2
ActiveRecord::Base.clear_active_connections! unless testing
-
end
-
-
7
response
-
rescue
-
2
ActiveRecord::Base.clear_active_connections! unless testing
-
2
raise
-
end
-
end
-
end
-
end
-
1
module ActiveRecord
-
1
module ConnectionAdapters # :nodoc:
-
1
module DatabaseLimits
-
-
# Returns the maximum length of a table alias.
-
1
def table_alias_length
-
255
-
end
-
-
# Returns the maximum length of a column name.
-
1
def column_name_length
-
64
-
end
-
-
# Returns the maximum length of a table name.
-
1
def table_name_length
-
64
-
end
-
-
# Returns the maximum length of an index name.
-
1
def index_name_length
-
64
-
end
-
-
# Returns the maximum number of columns per table.
-
1
def columns_per_table
-
1024
-
end
-
-
# Returns the maximum number of indexes per table.
-
1
def indexes_per_table
-
16
-
end
-
-
# Returns the maximum number of columns in a multicolumn index.
-
1
def columns_per_multicolumn_index
-
16
-
end
-
-
# Returns the maximum number of elements in an IN (x,y,z) clause.
-
# nil means no limit.
-
1
def in_clause_length
-
nil
-
end
-
-
# Returns the maximum length of an SQL query.
-
1
def sql_query_length
-
1048575
-
end
-
-
# Returns maximum number of joins in a single query.
-
1
def joins_per_query
-
256
-
end
-
-
end
-
end
-
end
-
1
module ActiveRecord
-
1
module ConnectionAdapters # :nodoc:
-
1
module DatabaseStatements
-
1
def initialize
-
113
super
-
113
reset_transaction
-
end
-
-
# Converts an arel AST to SQL
-
1
def to_sql(arel, binds = [])
-
14081
if arel.respond_to?(:ast)
-
12316
binds = binds.dup
-
12316
visitor.accept(arel.ast) do
-
quote(*binds.shift.reverse)
-
end
-
else
-
1765
arel
-
end
-
end
-
-
# Returns an array of record hashes with the column names as keys and
-
# column values as values.
-
1
def select_all(arel, name = nil, binds = [])
-
8950
select(to_sql(arel, binds), name, binds)
-
end
-
-
# Returns a record hash with the column names as keys and column values
-
# as values.
-
1
def select_one(arel, name = nil, binds = [])
-
1846
result = select_all(arel, name, binds)
-
1846
result.first if result
-
end
-
-
# Returns a single value from a record
-
1
def select_value(arel, name = nil, binds = [])
-
1842
if result = select_one(arel, name, binds)
-
1739
result.values.first
-
end
-
end
-
-
# Returns an array of the values of the first column in a select:
-
# select_values("SELECT id FROM companies LIMIT 3") => [1,2,3]
-
1
def select_values(arel, name = nil)
-
5
result = select_rows(to_sql(arel, []), name)
-
27
result.map { |v| v[0] }
-
end
-
-
# Returns an array of arrays containing the field values.
-
# Order is the same as that returned by +columns+.
-
1
def select_rows(sql, name = nil)
-
end
-
1
undef_method :select_rows
-
-
# Executes the SQL statement in the context of this connection.
-
1
def execute(sql, name = nil)
-
end
-
1
undef_method :execute
-
-
# Executes +sql+ statement in the context of this connection using
-
# +binds+ as the bind substitutes. +name+ is logged along with
-
# the executed +sql+ statement.
-
1
def exec_query(sql, name = 'SQL', binds = [])
-
end
-
-
# Executes insert +sql+ statement in the context of this connection using
-
# +binds+ as the bind substitutes. +name+ is logged along with
-
# the executed +sql+ statement.
-
1
def exec_insert(sql, name, binds, pk = nil, sequence_name = nil)
-
exec_query(sql, name, binds)
-
end
-
-
# Executes delete +sql+ statement in the context of this connection using
-
# +binds+ as the bind substitutes. +name+ is logged along with
-
# the executed +sql+ statement.
-
1
def exec_delete(sql, name, binds)
-
exec_query(sql, name, binds)
-
end
-
-
# Executes update +sql+ statement in the context of this connection using
-
# +binds+ as the bind substitutes. +name+ is logged along with
-
# the executed +sql+ statement.
-
1
def exec_update(sql, name, binds)
-
exec_query(sql, name, binds)
-
end
-
-
# Returns the last auto-generated ID from the affected table.
-
#
-
# +id_value+ will be returned unless the value is nil, in
-
# which case the database will attempt to calculate the last inserted
-
# id and return that value.
-
#
-
# If the next id was calculated in advance (as in Oracle), it should be
-
# passed in as +id_value+.
-
1
def insert(arel, name = nil, pk = nil, id_value = nil, sequence_name = nil, binds = [])
-
2508
sql, binds = sql_for_insert(to_sql(arel, binds), pk, id_value, sequence_name, binds)
-
2508
value = exec_insert(sql, name, binds, pk, sequence_name)
-
2508
id_value || last_inserted_id(value)
-
end
-
-
# Executes the update statement and returns the number of rows affected.
-
1
def update(arel, name = nil, binds = [])
-
686
exec_update(to_sql(arel, binds), name, binds)
-
end
-
-
# Executes the delete statement and returns the number of rows affected.
-
1
def delete(arel, name = nil, binds = [])
-
1414
exec_delete(to_sql(arel, binds), name, binds)
-
end
-
-
# Returns +true+ when the connection adapter supports prepared statement
-
# caching, otherwise returns +false+
-
1
def supports_statement_cache?
-
false
-
end
-
-
# Runs the given block in a database transaction, and returns the result
-
# of the block.
-
#
-
# == Nested transactions support
-
#
-
# Most databases don't support true nested transactions. At the time of
-
# writing, the only database that supports true nested transactions that
-
# we're aware of, is MS-SQL.
-
#
-
# In order to get around this problem, #transaction will emulate the effect
-
# of nested transactions, by using savepoints:
-
# http://dev.mysql.com/doc/refman/5.0/en/savepoint.html
-
# Savepoints are supported by MySQL and PostgreSQL, but not SQLite3.
-
#
-
# It is safe to call this method if a database transaction is already open,
-
# i.e. if #transaction is called within another #transaction block. In case
-
# of a nested call, #transaction will behave as follows:
-
#
-
# - The block will be run without doing anything. All database statements
-
# that happen within the block are effectively appended to the already
-
# open database transaction.
-
# - However, if +:requires_new+ is set, the block will be wrapped in a
-
# database savepoint acting as a sub-transaction.
-
#
-
# === Caveats
-
#
-
# MySQL doesn't support DDL transactions. If you perform a DDL operation,
-
# then any created savepoints will be automatically released. For example,
-
# if you've created a savepoint, then you execute a CREATE TABLE statement,
-
# then the savepoint that was created will be automatically released.
-
#
-
# This means that, on MySQL, you shouldn't execute DDL operations inside
-
# a #transaction call that you know might create a savepoint. Otherwise,
-
# #transaction will raise exceptions when it tries to release the
-
# already-automatically-released savepoints:
-
#
-
# Model.connection.transaction do # BEGIN
-
# Model.connection.transaction(requires_new: true) do # CREATE SAVEPOINT active_record_1
-
# Model.connection.create_table(...)
-
# # active_record_1 now automatically released
-
# end # RELEASE SAVEPOINT active_record_1 <--- BOOM! database error!
-
# end
-
#
-
# == Transaction isolation
-
#
-
# If your database supports setting the isolation level for a transaction, you can set
-
# it like so:
-
#
-
# Post.transaction(isolation: :serializable) do
-
# # ...
-
# end
-
#
-
# Valid isolation levels are:
-
#
-
# * <tt>:read_uncommitted</tt>
-
# * <tt>:read_committed</tt>
-
# * <tt>:repeatable_read</tt>
-
# * <tt>:serializable</tt>
-
#
-
# You should consult the documentation for your database to understand the
-
# semantics of these different levels:
-
#
-
# * http://www.postgresql.org/docs/9.1/static/transaction-iso.html
-
# * https://dev.mysql.com/doc/refman/5.0/en/set-transaction.html
-
#
-
# An <tt>ActiveRecord::TransactionIsolationError</tt> will be raised if:
-
#
-
# * The adapter does not support setting the isolation level
-
# * You are joining an existing open transaction
-
# * You are creating a nested (savepoint) transaction
-
#
-
# The mysql, mysql2 and postgresql adapters support setting the transaction
-
# isolation level. However, support is disabled for mysql versions below 5,
-
# because they are affected by a bug[http://bugs.mysql.com/bug.php?id=39170]
-
# which means the isolation level gets persisted outside the transaction.
-
1
def transaction(options = {})
-
4563
options.assert_valid_keys :requires_new, :joinable, :isolation
-
-
4561
if !options[:requires_new] && current_transaction.joinable?
-
1266
if options[:isolation]
-
1
raise ActiveRecord::TransactionIsolationError, "cannot set isolation when joining a transaction"
-
end
-
-
1265
yield
-
else
-
6589
within_new_transaction(options) { yield }
-
end
-
rescue ActiveRecord::Rollback
-
# rollbacks are silently swallowed
-
end
-
-
1
def within_new_transaction(options = {}) #:nodoc:
-
3295
transaction = begin_transaction(options)
-
3294
yield
-
rescue Exception => error
-
261
rollback_transaction if transaction
-
261
raise
-
ensure
-
3295
begin
-
3295
commit_transaction unless error
-
rescue Exception
-
3
rollback_transaction
-
3
raise
-
end
-
end
-
-
1
def current_transaction #:nodoc:
-
4299
@transaction
-
end
-
-
1
def transaction_open?
-
16393
@transaction.open?
-
end
-
-
1
def begin_transaction(options = {}) #:nodoc:
-
19686
@transaction = @transaction.begin(options)
-
end
-
-
1
def commit_transaction #:nodoc:
-
3034
@transaction = @transaction.commit
-
end
-
-
1
def rollback_transaction #:nodoc:
-
16651
@transaction = @transaction.rollback
-
end
-
-
1
def reset_transaction #:nodoc:
-
196
@transaction = ClosedTransaction.new(self)
-
end
-
-
# Register a record with the current transaction so that its after_commit and after_rollback callbacks
-
# can be called.
-
1
def add_transaction_record(record)
-
3430
@transaction.add_record(record)
-
end
-
-
# Begins the transaction (and turns off auto-committing).
-
1
def begin_db_transaction() end
-
-
1
def transaction_isolation_levels
-
{
-
read_uncommitted: "READ UNCOMMITTED",
-
read_committed: "READ COMMITTED",
-
repeatable_read: "REPEATABLE READ",
-
serializable: "SERIALIZABLE"
-
6
}
-
end
-
-
# Begins the transaction with the isolation level set. Raises an error by
-
# default; adapters that support setting the isolation level should implement
-
# this method.
-
1
def begin_isolated_db_transaction(isolation)
-
raise ActiveRecord::TransactionIsolationError, "adapter does not support setting transaction isolation"
-
end
-
-
# Commits the transaction (and turns on auto-committing).
-
1
def commit_db_transaction() end
-
-
# Rolls back the transaction (and turns on auto-committing). Must be
-
# done if the transaction block raises an exception or returns false.
-
1
def rollback_db_transaction() end
-
-
1
def default_sequence_name(table, column)
-
nil
-
end
-
-
# Set the sequence to the max value of the table's column.
-
1
def reset_sequence!(table, column, sequence = nil)
-
# Do nothing by default. Implement for PostgreSQL, Oracle, ...
-
end
-
-
# Inserts the given fixture into the table. Overridden in adapters that require
-
# something beyond a simple insert (eg. Oracle).
-
1
def insert_fixture(fixture, table_name)
-
36595
columns = Hash[columns(table_name).map { |c| [c.name, c] }]
-
-
4211
key_list = []
-
4211
value_list = fixture.map do |name, value|
-
21093
key_list << quote_column_name(name)
-
21093
quote(value, columns[name])
-
end
-
-
4211
execute "INSERT INTO #{quote_table_name(table_name)} (#{key_list.join(', ')}) VALUES (#{value_list.join(', ')})", 'Fixture Insert'
-
end
-
-
1
def empty_insert_statement_value
-
298
"DEFAULT VALUES"
-
end
-
-
1
def case_sensitive_equality_operator
-
"="
-
end
-
-
1
def limited_update_conditions(where_sql, quoted_table_name, quoted_primary_key)
-
"WHERE #{quoted_primary_key} IN (SELECT #{quoted_primary_key} FROM #{quoted_table_name} #{where_sql})"
-
end
-
-
# Sanitizes the given LIMIT parameter in order to prevent SQL injection.
-
#
-
# The +limit+ may be anything that can evaluate to a string via #to_s. It
-
# should look like an integer, or a comma-delimited list of integers, or
-
# an Arel SQL literal.
-
#
-
# Returns Integer and Arel::Nodes::SqlLiteral limits as is.
-
# Returns the sanitized limit parameter, either as an integer, or as a
-
# string which contains a comma-delimited list of integers.
-
1
def sanitize_limit(limit)
-
5339
if limit.is_a?(Integer) || limit.is_a?(Arel::Nodes::SqlLiteral)
-
5335
limit
-
4
elsif limit.to_s =~ /,/
-
3
Arel.sql limit.to_s.split(',').map{ |i| Integer(i) }.join(',')
-
else
-
3
Integer(limit)
-
end
-
end
-
-
# The default strategy for an UPDATE with joins is to use a subquery. This doesn't work
-
# on mysql (even when aliasing the tables), but mysql allows using JOIN directly in
-
# an UPDATE statement, so in the mysql adapters we redefine this to do that.
-
1
def join_to_update(update, select) #:nodoc:
-
5
key = update.key
-
5
subselect = subquery_for(key, select)
-
-
5
update.where key.in(subselect)
-
end
-
-
1
def join_to_delete(delete, select, key) #:nodoc:
-
2
subselect = subquery_for(key, select)
-
-
2
delete.where key.in(subselect)
-
end
-
-
1
protected
-
-
# Return a subquery for the given key using the join information.
-
1
def subquery_for(key, select)
-
7
subselect = select.clone
-
7
subselect.projections = [key]
-
7
subselect
-
end
-
-
# Returns an array of record hashes with the column names as keys and
-
# column values as values.
-
1
def select(sql, name = nil, binds = [])
-
end
-
1
undef_method :select
-
-
# Returns the last auto-generated ID from the affected table.
-
1
def insert_sql(sql, name = nil, pk = nil, id_value = nil, sequence_name = nil)
-
1
execute(sql, name)
-
1
id_value
-
end
-
-
# Executes the update statement and returns the number of rows affected.
-
1
def update_sql(sql, name = nil)
-
execute(sql, name)
-
end
-
-
# Executes the delete statement and returns the number of rows affected.
-
1
def delete_sql(sql, name = nil)
-
update_sql(sql, name)
-
end
-
-
1
def sql_for_insert(sql, pk, id_value, sequence_name, binds)
-
[sql, binds]
-
end
-
-
1
def last_inserted_id(result)
-
2495
row = result.rows.first
-
2495
row && row.first
-
end
-
end
-
end
-
end
-
1
module ActiveRecord
-
1
module ConnectionAdapters # :nodoc:
-
1
module QueryCache
-
1
class << self
-
1
def included(base) #:nodoc:
-
1
dirties_query_cache base, :insert, :update, :delete
-
end
-
-
1
def dirties_query_cache(base, *method_names)
-
1
method_names.each do |method_name|
-
3
base.class_eval <<-end_code, __FILE__, __LINE__ + 1
-
def #{method_name}(*) # def update_with_query_dirty(*args)
-
clear_query_cache if @query_cache_enabled # clear_query_cache if @query_cache_enabled
-
super # update_without_query_dirty(*args)
-
end # end
-
end_code
-
end
-
end
-
end
-
-
1
attr_reader :query_cache, :query_cache_enabled
-
-
# Enable the query cache within the block.
-
1
def cache
-
20
old, @query_cache_enabled = @query_cache_enabled, true
-
20
yield
-
ensure
-
20
clear_query_cache
-
20
@query_cache_enabled = old
-
end
-
-
1
def enable_query_cache!
-
10
@query_cache_enabled = true
-
end
-
-
1
def disable_query_cache!
-
23
@query_cache_enabled = false
-
end
-
-
# Disable the query cache within the block.
-
1
def uncached
-
105
old, @query_cache_enabled = @query_cache_enabled, false
-
105
yield
-
ensure
-
105
@query_cache_enabled = old
-
end
-
-
# Clears the query cache.
-
#
-
# One reason you may wish to call this method explicitly is between queries
-
# that ask the database to randomize results. Otherwise the cache would see
-
# the same SQL query and repeatedly return the same result each time, silently
-
# undermining the randomness you were expecting.
-
1
def clear_query_cache
-
38
@query_cache.clear
-
end
-
-
1
def select_all(arel, name = nil, binds = [])
-
8966
if @query_cache_enabled && !locked?(arel)
-
39
sql = to_sql(arel, binds)
-
62
cache_sql(sql, binds) { super(sql, name, binds) }
-
else
-
8927
super
-
end
-
end
-
-
1
private
-
-
1
def cache_sql(sql, binds)
-
39
result =
-
if @query_cache[sql].key?(binds)
-
16
ActiveSupport::Notifications.instrument("sql.active_record",
-
:sql => sql, :binds => binds, :name => "CACHE", :connection_id => object_id)
-
16
@query_cache[sql][binds]
-
else
-
23
@query_cache[sql][binds] = yield
-
end
-
-
# FIXME: we should guarantee that all cached items are Result
-
# objects. Then we can avoid this conditional
-
39
if ActiveRecord::Result === result
-
39
result.dup
-
else
-
result.collect { |row| row.dup }
-
end
-
end
-
-
1
def locked?(arel)
-
41
arel.respond_to?(:locked) && arel.locked
-
end
-
end
-
end
-
end
-
1
require 'active_support/core_ext/big_decimal/conversions'
-
-
1
module ActiveRecord
-
1
module ConnectionAdapters # :nodoc:
-
1
module Quoting
-
# Quotes the column value to help prevent
-
# {SQL injection attacks}[http://en.wikipedia.org/wiki/SQL_injection].
-
1
def quote(value, column = nil)
-
# records are quoted as their primary key
-
27941
return value.quoted_id if value.respond_to?(:quoted_id)
-
-
27933
case value
-
when String, ActiveSupport::Multibyte::Chars
-
16381
value = value.to_s
-
16381
return "'#{quote_string(value)}'" unless column
-
-
16257
case column.type
-
4
when :binary then "'#{quote_string(column.string_to_binary(value))}'"
-
1404
when :integer then value.to_i.to_s
-
2
when :float then value.to_f.to_s
-
else
-
14847
"'#{quote_string(value)}'"
-
end
-
-
when true, false
-
648
if column && column.type == :integer
-
2
value ? '1' : '0'
-
else
-
646
value ? quoted_true : quoted_false
-
end
-
# BigDecimals need to be put in a non-normalized form and quoted.
-
122
when nil then "NULL"
-
2
when BigDecimal then value.to_s('F')
-
9637
when Numeric, ActiveSupport::Duration then value.to_s
-
1112
when Date, Time then "'#{quoted_date(value)}'"
-
1
when Symbol then "'#{quote_string(value.to_s)}'"
-
1
when Class then "'#{value.to_s}'"
-
else
-
29
"'#{quote_string(YAML.dump(value))}'"
-
end
-
end
-
-
# Cast a +value+ to a type that the database understands. For example,
-
# SQLite does not understand dates, so this method will convert a Date
-
# to a String.
-
1
def type_cast(value, column)
-
11699
return value.id if value.respond_to?(:quoted_id)
-
-
11699
case value
-
when String, ActiveSupport::Multibyte::Chars
-
2625
value = value.to_s
-
2625
return value unless column
-
-
2625
case column.type
-
when :binary then value
-
8
when :integer then value.to_i
-
when :float then value.to_f
-
else
-
2617
value
-
end
-
-
when true, false
-
20
if column && column.type == :integer
-
value ? 1 : 0
-
else
-
20
value ? 't' : 'f'
-
end
-
# BigDecimals need to be put in a non-normalized form and quoted.
-
when nil then nil
-
10
when BigDecimal then value.to_s('F')
-
6990
when Numeric then value
-
1945
when Date, Time then quoted_date(value)
-
when Symbol then value.to_s
-
else
-
to_type = column ? " to #{column.type}" : ""
-
raise TypeError, "can't cast #{value.class}#{to_type}"
-
end
-
end
-
-
# Quotes a string, escaping any ' (single quote) and \ (backslash)
-
# characters.
-
1
def quote_string(s)
-
17
s.gsub(/\\/, '\&\&').gsub(/'/, "''") # ' (for ruby-mode)
-
end
-
-
# Quotes the column name. Defaults to no quoting.
-
1
def quote_column_name(column_name)
-
5
column_name
-
end
-
-
# Quotes the table name. Defaults to column name quoting.
-
1
def quote_table_name(table_name)
-
2
quote_column_name(table_name)
-
end
-
-
1
def quoted_true
-
450
"'t'"
-
end
-
-
1
def quoted_false
-
200
"'f'"
-
end
-
-
1
def quoted_date(value)
-
3057
if value.acts_like?(:time)
-
2917
zone_conversion_method = ActiveRecord::Base.default_timezone == :utc ? :getutc : :getlocal
-
-
2917
if value.respond_to?(zone_conversion_method)
-
2916
value = value.send(zone_conversion_method)
-
end
-
end
-
-
3057
value.to_s(:db)
-
end
-
end
-
end
-
end
-
1
require 'date'
-
1
require 'set'
-
1
require 'bigdecimal'
-
1
require 'bigdecimal/util'
-
-
1
module ActiveRecord
-
1
module ConnectionAdapters #:nodoc:
-
# Abstract representation of an index definition on a table. Instances of
-
# this type are typically created and returned by methods in database
-
# adapters. e.g. ActiveRecord::ConnectionAdapters::AbstractMysqlAdapter#indexes
-
1
class IndexDefinition < Struct.new(:table, :name, :unique, :columns, :lengths, :orders, :where) #:nodoc:
-
end
-
-
# Abstract representation of a column definition. Instances of this type
-
# are typically created by methods in TableDefinition, and added to the
-
# +columns+ attribute of said TableDefinition object, in order to be used
-
# for generating a number of table creation or table changing SQL statements.
-
1
class ColumnDefinition < Struct.new(:base, :name, :type, :limit, :precision, :scale, :default, :null) #:nodoc:
-
-
1
def string_to_binary(value)
-
value
-
end
-
-
1
def sql_type
-
1200
base.type_to_sql(type.to_sym, limit, precision, scale)
-
end
-
-
1
def to_sql
-
1126
column_sql = "#{base.quote_column_name(name)} #{sql_type}"
-
1124
column_options = {}
-
1124
column_options[:null] = null unless null.nil?
-
1124
column_options[:default] = default unless default.nil?
-
1124
add_column_options!(column_sql, column_options) unless type.to_sym == :primary_key
-
1124
column_sql
-
end
-
-
1
private
-
-
1
def add_column_options!(sql, options)
-
791
base.add_column_options!(sql, options.merge(:column => self))
-
end
-
end
-
-
# Represents the schema of an SQL table in an abstract way. This class
-
# provides methods for manipulating the schema representation.
-
#
-
# Inside migration files, the +t+ object in +create_table+ and
-
# +change_table+ is actually of this type:
-
#
-
# class SomeMigration < ActiveRecord::Migration
-
# def up
-
# create_table :foo do |t|
-
# puts t.class # => "ActiveRecord::ConnectionAdapters::TableDefinition"
-
# end
-
# end
-
#
-
# def down
-
# ...
-
# end
-
# end
-
#
-
# The table definitions
-
# The Columns are stored as a ColumnDefinition in the +columns+ attribute.
-
1
class TableDefinition
-
# An array of ColumnDefinition objects, representing the column changes
-
# that have been defined.
-
1
attr_accessor :columns, :indexes
-
-
1
def initialize(base)
-
375
@columns = []
-
375
@columns_hash = {}
-
375
@indexes = {}
-
375
@base = base
-
end
-
-
1
def xml(*args)
-
raise NotImplementedError unless %w{
-
sqlite mysql mysql2
-
}.include? @base.adapter_name.downcase
-
-
options = args.extract_options!
-
column(args[0], :text, options)
-
end
-
-
# Appends a primary key definition to the table definition.
-
# Can be called multiple times, but this is probably not a good idea.
-
1
def primary_key(name)
-
336
column(name, :primary_key)
-
end
-
-
# Returns a ColumnDefinition for the column with name +name+.
-
1
def [](name)
-
2254
@columns_hash[name.to_s]
-
end
-
-
# Instantiates a new column for the table.
-
# The +type+ parameter is normally one of the migrations native types,
-
# which is one of the following:
-
# <tt>:primary_key</tt>, <tt>:string</tt>, <tt>:text</tt>,
-
# <tt>:integer</tt>, <tt>:float</tt>, <tt>:decimal</tt>,
-
# <tt>:datetime</tt>, <tt>:timestamp</tt>, <tt>:time</tt>,
-
# <tt>:date</tt>, <tt>:binary</tt>, <tt>:boolean</tt>.
-
#
-
# You may use a type not in this list as long as it is supported by your
-
# database (for example, "polygon" in MySQL), but this will not be database
-
# agnostic and should usually be avoided.
-
#
-
# Available options are (none of these exists by default):
-
# * <tt>:limit</tt> -
-
# Requests a maximum column length. This is number of characters for <tt>:string</tt> and
-
# <tt>:text</tt> columns and number of bytes for <tt>:binary</tt> and <tt>:integer</tt> columns.
-
# * <tt>:default</tt> -
-
# The column's default value. Use nil for NULL.
-
# * <tt>:null</tt> -
-
# Allows or disallows +NULL+ values in the column. This option could
-
# have been named <tt>:null_allowed</tt>.
-
# * <tt>:precision</tt> -
-
# Specifies the precision for a <tt>:decimal</tt> column.
-
# * <tt>:scale</tt> -
-
# Specifies the scale for a <tt>:decimal</tt> column.
-
#
-
# For clarity's sake: the precision is the number of significant digits,
-
# while the scale is the number of digits that can be stored following
-
# the decimal point. For example, the number 123.45 has a precision of 5
-
# and a scale of 2. A decimal with a precision of 5 and a scale of 2 can
-
# range from -999.99 to 999.99.
-
#
-
# Please be aware of different RDBMS implementations behavior with
-
# <tt>:decimal</tt> columns:
-
# * The SQL standard says the default scale should be 0, <tt>:scale</tt> <=
-
# <tt>:precision</tt>, and makes no comments about the requirements of
-
# <tt>:precision</tt>.
-
# * MySQL: <tt>:precision</tt> [1..63], <tt>:scale</tt> [0..30].
-
# Default is (10,0).
-
# * PostgreSQL: <tt>:precision</tt> [1..infinity],
-
# <tt>:scale</tt> [0..infinity]. No default.
-
# * SQLite2: Any <tt>:precision</tt> and <tt>:scale</tt> may be used.
-
# Internal storage as strings. No default.
-
# * SQLite3: No restrictions on <tt>:precision</tt> and <tt>:scale</tt>,
-
# but the maximum supported <tt>:precision</tt> is 16. No default.
-
# * Oracle: <tt>:precision</tt> [1..38], <tt>:scale</tt> [-84..127].
-
# Default is (38,0).
-
# * DB2: <tt>:precision</tt> [1..63], <tt>:scale</tt> [0..62].
-
# Default unknown.
-
# * Firebird: <tt>:precision</tt> [1..18], <tt>:scale</tt> [0..18].
-
# Default (9,0). Internal types NUMERIC and DECIMAL have different
-
# storage rules, decimal being better.
-
# * FrontBase?: <tt>:precision</tt> [1..38], <tt>:scale</tt> [0..38].
-
# Default (38,0). WARNING Max <tt>:precision</tt>/<tt>:scale</tt> for
-
# NUMERIC is 19, and DECIMAL is 38.
-
# * SqlServer?: <tt>:precision</tt> [1..38], <tt>:scale</tt> [0..38].
-
# Default (38,0).
-
# * Sybase: <tt>:precision</tt> [1..38], <tt>:scale</tt> [0..38].
-
# Default (38,0).
-
# * OpenBase?: Documentation unclear. Claims storage in <tt>double</tt>.
-
#
-
# This method returns <tt>self</tt>.
-
#
-
# == Examples
-
# # Assuming +td+ is an instance of TableDefinition
-
# td.column(:granted, :boolean)
-
# # granted BOOLEAN
-
#
-
# td.column(:picture, :binary, limit: 2.megabytes)
-
# # => picture BLOB(2097152)
-
#
-
# td.column(:sales_stage, :string, limit: 20, default: 'new', null: false)
-
# # => sales_stage VARCHAR(20) DEFAULT 'new' NOT NULL
-
#
-
# td.column(:bill_gates_money, :decimal, precision: 15, scale: 2)
-
# # => bill_gates_money DECIMAL(15,2)
-
#
-
# td.column(:sensor_reading, :decimal, precision: 30, scale: 20)
-
# # => sensor_reading DECIMAL(30,20)
-
#
-
# # While <tt>:scale</tt> defaults to zero on most databases, it
-
# # probably wouldn't hurt to include it.
-
# td.column(:huge_integer, :decimal, precision: 30)
-
# # => huge_integer DECIMAL(30)
-
#
-
# # Defines a column with a database-specific type.
-
# td.column(:foo, 'polygon')
-
# # => foo polygon
-
#
-
# == Short-hand examples
-
#
-
# Instead of calling +column+ directly, you can also work with the short-hand definitions for the default types.
-
# They use the type as the method name instead of as a parameter and allow for multiple columns to be defined
-
# in a single statement.
-
#
-
# What can be written like this with the regular calls to column:
-
#
-
# create_table "products", force: true do |t|
-
# t.column "shop_id", :integer
-
# t.column "creator_id", :integer
-
# t.column "name", :string, default: "Untitled"
-
# t.column "value", :string, default: "Untitled"
-
# t.column "created_at", :datetime
-
# t.column "updated_at", :datetime
-
# end
-
#
-
# Can also be written as follows using the short-hand:
-
#
-
# create_table :products do |t|
-
# t.integer :shop_id, :creator_id
-
# t.string :name, :value, default: "Untitled"
-
# t.timestamps
-
# end
-
#
-
# There's a short-hand method for each of the type values declared at the top. And then there's
-
# TableDefinition#timestamps that'll add +created_at+ and +updated_at+ as datetimes.
-
#
-
# TableDefinition#references will add an appropriately-named _id column, plus a corresponding _type
-
# column if the <tt>:polymorphic</tt> option is supplied. If <tt>:polymorphic</tt> is a hash of
-
# options, these will be used when creating the <tt>_type</tt> column. The <tt>:index</tt> option
-
# will also create an index, similar to calling <tt>add_index</tt>. So what can be written like this:
-
#
-
# create_table :taggings do |t|
-
# t.integer :tag_id, :tagger_id, :taggable_id
-
# t.string :tagger_type
-
# t.string :taggable_type, default: 'Photo'
-
# end
-
# add_index :taggings, :tag_id, name: 'index_taggings_on_tag_id'
-
# add_index :taggings, [:tagger_id, :tagger_type]
-
#
-
# Can also be written as follows using references:
-
#
-
# create_table :taggings do |t|
-
# t.references :tag, index: { name: 'index_taggings_on_tag_id' }
-
# t.references :tagger, polymorphic: true, index: true
-
# t.references :taggable, polymorphic: { default: 'Photo' }
-
# end
-
1
def column(name, type, options = {})
-
1129
name = name.to_s
-
1129
type = type.to_sym
-
-
1129
if primary_key_column_name == name
-
2
raise ArgumentError, "you can't redefine the primary key column '#{name}'. To define a custom primary key, pass { id: false } to create_table."
-
end
-
-
1127
column = self[name] || new_column_definition(@base, name, type)
-
-
1127
limit = options.fetch(:limit) do
-
1049
native[type][:limit] if native[type].is_a?(Hash)
-
end
-
-
1127
column.limit = limit
-
1127
column.precision = options[:precision]
-
1127
column.scale = options[:scale]
-
1127
column.default = options[:default]
-
1127
column.null = options[:null]
-
1127
self
-
end
-
-
1
%w( string text integer float decimal datetime timestamp time date binary boolean ).each do |column_type|
-
11
class_eval <<-EOV, __FILE__, __LINE__ + 1
-
def #{column_type}(*args) # def string(*args)
-
options = args.extract_options! # options = args.extract_options!
-
column_names = args # column_names = args
-
type = :'#{column_type}' # type = :string
-
column_names.each { |name| column(name, type, options) } # column_names.each { |name| column(name, type, options) }
-
end # end
-
EOV
-
end
-
-
# Adds index options to the indexes hash, keyed by column name
-
# This is primarily used to track indexes that need to be created after the table
-
#
-
# index(:account_id, name: 'index_projects_on_account_id')
-
1
def index(column_name, options = {})
-
5
indexes[column_name] = options
-
end
-
-
# Appends <tt>:datetime</tt> columns <tt>:created_at</tt> and
-
# <tt>:updated_at</tt> to the table.
-
1
def timestamps(*args)
-
55
options = args.extract_options!
-
55
column(:created_at, :datetime, options)
-
55
column(:updated_at, :datetime, options)
-
end
-
-
1
def references(*args)
-
17
options = args.extract_options!
-
17
polymorphic = options.delete(:polymorphic)
-
17
index_options = options.delete(:index)
-
17
args.each do |col|
-
17
column("#{col}_id", :integer, options)
-
17
column("#{col}_type", :string, polymorphic.is_a?(Hash) ? polymorphic : options) if polymorphic
-
19
index(polymorphic ? %w(id type).map { |t| "#{col}_#{t}" } : "#{col}_id", index_options.is_a?(Hash) ? index_options : nil) if index_options
-
end
-
end
-
1
alias :belongs_to :references
-
-
# Returns a String whose contents are the column definitions
-
# concatenated together. This string can then be prepended and appended to
-
# to generate the final SQL to create the table.
-
1
def to_sql
-
1495
@columns.map { |c| c.to_sql } * ', '
-
end
-
-
1
private
-
1
def new_column_definition(base, name, type)
-
definition = ColumnDefinition.new base, name, type
-
@columns << definition
-
@columns_hash[name] = definition
-
definition
-
end
-
-
1
def primary_key_column_name
-
1893
primary_key_column = columns.detect { |c| c.type == :primary_key }
-
1129
primary_key_column && primary_key_column.name
-
end
-
-
1
def native
-
1762
@base.native_database_types
-
end
-
end
-
-
# Represents an SQL table in an abstract way for updating a table.
-
# Also see TableDefinition and SchemaStatements#create_table
-
#
-
# Available transformations are:
-
#
-
# change_table :table do |t|
-
# t.column
-
# t.index
-
# t.timestamps
-
# t.change
-
# t.change_default
-
# t.rename
-
# t.references
-
# t.belongs_to
-
# t.string
-
# t.text
-
# t.integer
-
# t.float
-
# t.decimal
-
# t.datetime
-
# t.timestamp
-
# t.time
-
# t.date
-
# t.binary
-
# t.boolean
-
# t.remove
-
# t.remove_references
-
# t.remove_belongs_to
-
# t.remove_index
-
# t.remove_timestamps
-
# end
-
#
-
1
class Table
-
1
def initialize(table_name, base)
-
30
@table_name = table_name
-
30
@base = base
-
end
-
-
# Adds a new column to the named table.
-
# See TableDefinition#column for details of the options you can use.
-
#
-
# ====== Creating a simple column
-
# t.column(:name, :string)
-
1
def column(column_name, type, options = {})
-
2
@base.add_column(@table_name, column_name, type, options)
-
end
-
-
# Checks to see if a column exists. See SchemaStatements#column_exists?
-
1
def column_exists?(column_name, type = nil, options = {})
-
2
@base.column_exists?(@table_name, column_name, type, options)
-
end
-
-
# Adds a new index to the table. +column_name+ can be a single Symbol, or
-
# an Array of Symbols. See SchemaStatements#add_index
-
#
-
# ====== Creating a simple index
-
# t.index(:name)
-
# ====== Creating a unique index
-
# t.index([:branch_id, :party_id], unique: true)
-
# ====== Creating a named index
-
# t.index([:branch_id, :party_id], unique: true, name: 'by_branch_party')
-
1
def index(column_name, options = {})
-
2
@base.add_index(@table_name, column_name, options)
-
end
-
-
# Checks to see if an index exists. See SchemaStatements#index_exists?
-
1
def index_exists?(column_name, options = {})
-
2
@base.index_exists?(@table_name, column_name, options)
-
end
-
-
# Adds timestamps (+created_at+ and +updated_at+) columns to the table. See SchemaStatements#add_timestamps
-
#
-
# t.timestamps
-
1
def timestamps
-
1
@base.add_timestamps(@table_name)
-
end
-
-
# Changes the column's definition according to the new options.
-
# See TableDefinition#column for details of the options you can use.
-
#
-
# t.change(:name, :string, limit: 80)
-
# t.change(:description, :text)
-
1
def change(column_name, type, options = {})
-
2
@base.change_column(@table_name, column_name, type, options)
-
end
-
-
# Sets a new default value for a column. See SchemaStatements#change_column_default
-
#
-
# t.change_default(:qualification, 'new')
-
# t.change_default(:authorized, 1)
-
1
def change_default(column_name, default)
-
1
@base.change_column_default(@table_name, column_name, default)
-
end
-
-
# Removes the column(s) from the table definition.
-
#
-
# t.remove(:qualification)
-
# t.remove(:qualification, :experience)
-
1
def remove(*column_names)
-
2
@base.remove_column(@table_name, *column_names)
-
end
-
-
# Removes the given index from the table.
-
#
-
# ====== Remove the index_table_name_on_column in the table_name table
-
# t.remove_index :column
-
# ====== Remove the index named index_table_name_on_branch_id in the table_name table
-
# t.remove_index column: :branch_id
-
# ====== Remove the index named index_table_name_on_branch_id_and_party_id in the table_name table
-
# t.remove_index column: [:branch_id, :party_id]
-
# ====== Remove the index named by_branch_party in the table_name table
-
# t.remove_index name: :by_branch_party
-
1
def remove_index(options = {})
-
1
@base.remove_index(@table_name, options)
-
end
-
-
# Removes the timestamp columns (+created_at+ and +updated_at+) from the table.
-
#
-
# t.remove_timestamps
-
1
def remove_timestamps
-
1
@base.remove_timestamps(@table_name)
-
end
-
-
# Renames a column.
-
#
-
# t.rename(:description, :name)
-
1
def rename(column_name, new_column_name)
-
1
@base.rename_column(@table_name, column_name, new_column_name)
-
end
-
-
# Adds a reference. Optionally adds a +type+ column, if <tt>:polymorphic</tt> option is provided.
-
# <tt>references</tt> and <tt>belongs_to</tt> are acceptable.
-
#
-
# t.references(:user)
-
# t.belongs_to(:supplier, polymorphic: true)
-
#
-
1
def references(*args)
-
8
options = args.extract_options!
-
8
args.each do |ref_name|
-
8
@base.add_reference(@table_name, ref_name, options)
-
end
-
end
-
1
alias :belongs_to :references
-
-
# Removes a reference. Optionally removes a +type+ column.
-
# <tt>remove_references</tt> and <tt>remove_belongs_to</tt> are acceptable.
-
#
-
# t.remove_references(:user)
-
# t.remove_belongs_to(:supplier, polymorphic: true)
-
#
-
1
def remove_references(*args)
-
4
options = args.extract_options!
-
4
args.each do |ref_name|
-
4
@base.remove_reference(@table_name, ref_name, options)
-
end
-
end
-
1
alias :remove_belongs_to :remove_references
-
-
# Adds a column or columns of a specified type
-
#
-
# t.string(:goat)
-
# t.string(:goat, :sheep)
-
1
%w( string text integer float decimal datetime timestamp time date binary boolean ).each do |column_type|
-
11
class_eval <<-EOV, __FILE__, __LINE__ + 1
-
def #{column_type}(*args) # def string(*args)
-
options = args.extract_options! # options = args.extract_options!
-
column_names = args # column_names = args
-
type = :'#{column_type}' # type = :string
-
column_names.each do |name| # column_names.each do |name|
-
column = ColumnDefinition.new(@base, name.to_s, type) # column = ColumnDefinition.new(@base, name, type)
-
if options[:limit] # if options[:limit]
-
column.limit = options[:limit] # column.limit = options[:limit]
-
elsif native[type].is_a?(Hash) # elsif native[type].is_a?(Hash)
-
column.limit = native[type][:limit] # column.limit = native[type][:limit]
-
end # end
-
column.precision = options[:precision] # column.precision = options[:precision]
-
column.scale = options[:scale] # column.scale = options[:scale]
-
column.default = options[:default] # column.default = options[:default]
-
column.null = options[:null] # column.null = options[:null]
-
@base.add_column(@table_name, name, column.sql_type, options) # @base.add_column(@table_name, name, column.sql_type, options)
-
end # end
-
end # end
-
EOV
-
end
-
-
1
private
-
1
def native
-
4
@base.native_database_types
-
end
-
end
-
-
end
-
end
-
1
module ActiveRecord
-
1
module ConnectionAdapters # :nodoc:
-
# The goal of this module is to move Adapter specific column
-
# definitions to the Adapter instead of having it in the schema
-
# dumper itself. This code represents the normal case.
-
# We can then redefine how certain data types may be handled in the schema dumper on the
-
# Adapter level by over-writing this code inside the database spececific adapters
-
1
module ColumnDumper
-
1
def column_spec(column, types)
-
9922
spec = prepare_column_options(column, types)
-
12920
(spec.keys - [:name, :type]).each{ |k| spec[k].insert(0, "#{k.to_s}: ")}
-
9922
spec
-
end
-
-
# This can be overridden on a Adapter level basis to support other
-
# extended datatypes (Example: Adding an array option in the
-
# PostgreSQLAdapter)
-
1
def prepare_column_options(column, types)
-
9922
spec = {}
-
9922
spec[:name] = column.name.inspect
-
-
# AR has an optimization which handles zero-scale decimals as integers. This
-
# code ensures that the dumper still dumps the column as a decimal.
-
9922
spec[:type] = if column.type == :integer && /^(numeric|decimal)/ =~ column.sql_type
-
78
'decimal'
-
else
-
9844
column.type.to_s
-
end
-
9922
spec[:limit] = column.limit.inspect if column.limit != types[column.type][:limit] && spec[:type] != 'decimal'
-
9922
spec[:precision] = column.precision.inspect if column.precision
-
9922
spec[:scale] = column.scale.inspect if column.scale
-
9922
spec[:null] = 'false' unless column.null
-
9922
spec[:default] = default_string(column.default) if column.has_default?
-
9922
spec
-
end
-
-
# Lists the valid migration options
-
1
def migration_keys
-
3657
[:name, :limit, :precision, :scale, :default, :null]
-
end
-
-
1
private
-
-
1
def default_string(value)
-
1028
case value
-
when BigDecimal
-
51
value.to_s
-
when Date, DateTime, Time
-
50
"'#{value.to_s(:db)}'"
-
else
-
927
value.inspect
-
end
-
end
-
end
-
end
-
end
-
1
require 'active_record/migration/join_table'
-
-
1
module ActiveRecord
-
1
module ConnectionAdapters # :nodoc:
-
1
module SchemaStatements
-
1
include ActiveRecord::Migration::JoinTable
-
-
# Returns a Hash of mappings from the abstract data types to the native
-
# database types. See TableDefinition#column for details on the recognized
-
# abstract data types.
-
1
def native_database_types
-
{}
-
end
-
-
# Truncates a table alias according to the limits of the current adapter.
-
1
def table_alias_for(table_name)
-
184
table_name[0...table_alias_length].tr('.', '_')
-
end
-
-
# Checks to see if the table +table_name+ exists on the database.
-
#
-
# table_exists?(:developers)
-
1
def table_exists?(table_name)
-
2
tables.include?(table_name.to_s)
-
end
-
-
# Returns an array of indexes for the given table.
-
# def indexes(table_name, name = nil) end
-
-
# Checks to see if an index exists on a table for a given index definition.
-
#
-
# # Check an index exists
-
# index_exists?(:suppliers, :company_id)
-
#
-
# # Check an index on multiple columns exists
-
# index_exists?(:suppliers, [:company_id, :company_type])
-
#
-
# # Check a unique index exists
-
# index_exists?(:suppliers, :company_id, unique: true)
-
#
-
# # Check an index with a custom name exists
-
# index_exists?(:suppliers, :company_id, name: "idx_company_id"
-
1
def index_exists?(table_name, column_name, options = {})
-
26
column_names = Array(column_name)
-
26
index_name = options.key?(:name) ? options[:name].to_s : index_name(table_name, :column => column_names)
-
26
if options[:unique]
-
4
indexes(table_name).any?{ |i| i.unique && i.name == index_name }
-
else
-
43
indexes(table_name).any?{ |i| i.name == index_name }
-
end
-
end
-
-
# Returns an array of Column objects for the table specified by +table_name+.
-
# See the concrete implementation for details on the expected parameter values.
-
1
def columns(table_name) end
-
-
# Checks to see if a column exists in a given table.
-
#
-
# # Check a column exists
-
# column_exists?(:suppliers, :name)
-
#
-
# # Check a column exists of a particular type
-
# column_exists?(:suppliers, :name, :string)
-
#
-
# # Check a column exists with a specific definition
-
# column_exists?(:suppliers, :name, :string, limit: 100)
-
# column_exists?(:suppliers, :name, :string, default: 'default')
-
# column_exists?(:suppliers, :name, :string, null: false)
-
# column_exists?(:suppliers, :tax, :decimal, precision: 8, scale: 2)
-
1
def column_exists?(table_name, column_name, type = nil, options = {})
-
26
columns(table_name).any?{ |c| c.name == column_name.to_s &&
-
97
(!type || c.type == type) &&
-
17
(!options.key?(:limit) || c.limit == options[:limit]) &&
-
16
(!options.key?(:precision) || c.precision == options[:precision]) &&
-
15
(!options.key?(:scale) || c.scale == options[:scale]) &&
-
15
(!options.key?(:default) || c.default == options[:default]) &&
-
14
(!options.key?(:null) || c.null == options[:null]) }
-
end
-
-
# Creates a new table with the name +table_name+. +table_name+ may either
-
# be a String or a Symbol.
-
#
-
# There are two ways to work with +create_table+. You can use the block
-
# form or the regular form, like this:
-
#
-
# === Block form
-
# # create_table() passes a TableDefinition object to the block.
-
# # This form will not only create the table, but also columns for the
-
# # table.
-
#
-
# create_table(:suppliers) do |t|
-
# t.column :name, :string, limit: 60
-
# # Other fields here
-
# end
-
#
-
# === Block form, with shorthand
-
# # You can also use the column types as method calls, rather than calling the column method.
-
# create_table(:suppliers) do |t|
-
# t.string :name, limit: 60
-
# # Other fields here
-
# end
-
#
-
# === Regular form
-
# # Creates a table called 'suppliers' with no columns.
-
# create_table(:suppliers)
-
# # Add a column to 'suppliers'.
-
# add_column(:suppliers, :name, :string, {limit: 60})
-
#
-
# The +options+ hash can include the following keys:
-
# [<tt>:id</tt>]
-
# Whether to automatically add a primary key column. Defaults to true.
-
# Join tables for +has_and_belongs_to_many+ should set it to false.
-
# [<tt>:primary_key</tt>]
-
# The name of the primary key, if one is to be added automatically.
-
# Defaults to +id+. If <tt>:id</tt> is false this option is ignored.
-
#
-
# Also note that this just sets the primary key in the table. You additionally
-
# need to configure the primary key in the model via +self.primary_key=+.
-
# Models do NOT auto-detect the primary key from their table definition.
-
#
-
# [<tt>:options</tt>]
-
# Any extra options you want appended to the table definition.
-
# [<tt>:temporary</tt>]
-
# Make a temporary table.
-
# [<tt>:force</tt>]
-
# Set to true to drop the table before creating it.
-
# Defaults to false.
-
#
-
# ====== Add a backend specific option to the generated SQL (MySQL)
-
# create_table(:suppliers, options: 'ENGINE=InnoDB DEFAULT CHARSET=utf8')
-
# generates:
-
# CREATE TABLE suppliers (
-
# id int(11) DEFAULT NULL auto_increment PRIMARY KEY
-
# ) ENGINE=InnoDB DEFAULT CHARSET=utf8
-
#
-
# ====== Rename the primary key column
-
# create_table(:objects, primary_key: 'guid') do |t|
-
# t.column :name, :string, limit: 80
-
# end
-
# generates:
-
# CREATE TABLE objects (
-
# guid int(11) DEFAULT NULL auto_increment PRIMARY KEY,
-
# name varchar(80)
-
# )
-
#
-
# ====== Do not add a primary key column
-
# create_table(:categories_suppliers, id: false) do |t|
-
# t.column :category_id, :integer
-
# t.column :supplier_id, :integer
-
# end
-
# generates:
-
# CREATE TABLE categories_suppliers (
-
# category_id int,
-
# supplier_id int
-
# )
-
#
-
# See also TableDefinition#column for details on how to create columns.
-
1
def create_table(table_name, options = {})
-
375
td = table_definition
-
375
td.primary_key(options[:primary_key] || Base.get_primary_key(table_name.to_s.singularize)) unless options[:id] == false
-
-
375
yield td if block_given?
-
-
372
if options[:force] && table_exists?(table_name)
-
133
drop_table(table_name, options)
-
end
-
-
372
create_sql = "CREATE#{' TEMPORARY' if options[:temporary]} TABLE "
-
372
create_sql << "#{quote_table_name(table_name)} ("
-
372
create_sql << td.to_sql
-
370
create_sql << ") #{options[:options]}"
-
370
execute create_sql
-
345
td.indexes.each_pair { |c,o| add_index table_name, c, o }
-
end
-
-
# Creates a new join table with the name created using the lexical order of the first two
-
# arguments. These arguments can be a String or a Symbol.
-
#
-
# # Creates a table called 'assemblies_parts' with no id.
-
# create_join_table(:assemblies, :parts)
-
#
-
# You can pass a +options+ hash can include the following keys:
-
# [<tt>:table_name</tt>]
-
# Sets the table name overriding the default
-
# [<tt>:column_options</tt>]
-
# Any extra options you want appended to the columns definition.
-
# [<tt>:options</tt>]
-
# Any extra options you want appended to the table definition.
-
# [<tt>:temporary</tt>]
-
# Make a temporary table.
-
# [<tt>:force</tt>]
-
# Set to true to drop the table before creating it.
-
# Defaults to false.
-
#
-
# ====== Add a backend specific option to the generated SQL (MySQL)
-
# create_join_table(:assemblies, :parts, options: 'ENGINE=InnoDB DEFAULT CHARSET=utf8')
-
# generates:
-
# CREATE TABLE assemblies_parts (
-
# assembly_id int NOT NULL,
-
# part_id int NOT NULL,
-
# ) ENGINE=InnoDB DEFAULT CHARSET=utf8
-
1
def create_join_table(table_1, table_2, options = {})
-
9
join_table_name = find_join_table_name(table_1, table_2, options)
-
-
9
column_options = options.delete(:column_options) || {}
-
9
column_options.reverse_merge!(null: false)
-
-
27
t1_column, t2_column = [table_1, table_2].map{ |t| t.to_s.singularize.foreign_key }
-
-
9
create_table(join_table_name, options.merge!(id: false)) do |td|
-
9
td.integer t1_column, column_options
-
9
td.integer t2_column, column_options
-
9
yield td if block_given?
-
end
-
end
-
-
# A block for changing columns in +table+.
-
#
-
# # change_table() yields a Table instance
-
# change_table(:suppliers) do |t|
-
# t.column :name, :string, limit: 60
-
# # Other column alterations here
-
# end
-
#
-
# The +options+ hash can include the following keys:
-
# [<tt>:bulk</tt>]
-
# Set this to true to make this a bulk alter query, such as
-
# ALTER TABLE `users` ADD COLUMN age INT(11), ADD COLUMN birthdate DATETIME ...
-
#
-
# Defaults to false.
-
#
-
# ====== Add a column
-
# change_table(:suppliers) do |t|
-
# t.column :name, :string, limit: 60
-
# end
-
#
-
# ====== Add 2 integer columns
-
# change_table(:suppliers) do |t|
-
# t.integer :width, :height, null: false, default: 0
-
# end
-
#
-
# ====== Add created_at/updated_at columns
-
# change_table(:suppliers) do |t|
-
# t.timestamps
-
# end
-
#
-
# ====== Add a foreign key column
-
# change_table(:suppliers) do |t|
-
# t.references :company
-
# end
-
#
-
# Creates a <tt>company_id(integer)</tt> column
-
#
-
# ====== Add a polymorphic foreign key column
-
# change_table(:suppliers) do |t|
-
# t.belongs_to :company, polymorphic: true
-
# end
-
#
-
# Creates <tt>company_type(varchar)</tt> and <tt>company_id(integer)</tt> columns
-
#
-
# ====== Remove a column
-
# change_table(:suppliers) do |t|
-
# t.remove :company
-
# end
-
#
-
# ====== Remove several columns
-
# change_table(:suppliers) do |t|
-
# t.remove :company_id
-
# t.remove :width, :height
-
# end
-
#
-
# ====== Remove an index
-
# change_table(:suppliers) do |t|
-
# t.remove_index :company_id
-
# end
-
#
-
# See also Table for details on
-
# all of the various column transformation
-
1
def change_table(table_name, options = {})
-
5
if supports_bulk_alter? && options[:bulk]
-
recorder = ActiveRecord::Migration::CommandRecorder.new(self)
-
yield Table.new(table_name, recorder)
-
bulk_change_table(table_name, recorder.commands)
-
else
-
5
yield Table.new(table_name, self)
-
end
-
end
-
-
# Renames a table.
-
#
-
# rename_table('octopuses', 'octopi')
-
1
def rename_table(table_name, new_name)
-
raise NotImplementedError, "rename_table is not implemented"
-
end
-
-
# Drops a table from the database.
-
1
def drop_table(table_name, options = {})
-
485
execute "DROP TABLE #{quote_table_name(table_name)}"
-
end
-
-
# Adds a new column to the named table.
-
# See TableDefinition#column for details of the options you can use.
-
1
def add_column(table_name, column_name, type, options = {})
-
add_column_sql = "ALTER TABLE #{quote_table_name(table_name)} ADD #{quote_column_name(column_name)} #{type_to_sql(type, options[:limit], options[:precision], options[:scale])}"
-
add_column_options!(add_column_sql, options)
-
execute(add_column_sql)
-
end
-
-
# Removes the column(s) from the table definition.
-
#
-
# remove_column(:suppliers, :qualification)
-
# remove_columns(:suppliers, :qualification, :experience)
-
1
def remove_column(table_name, *column_names)
-
513
columns_for_remove(table_name, *column_names).each {|column_name| execute "ALTER TABLE #{quote_table_name(table_name)} DROP #{column_name}" }
-
end
-
1
alias :remove_columns :remove_column
-
-
# Changes the column's definition according to the new options.
-
# See TableDefinition#column for details of the options you can use.
-
#
-
# change_column(:suppliers, :name, :string, limit: 80)
-
# change_column(:accounts, :description, :text)
-
1
def change_column(table_name, column_name, type, options = {})
-
raise NotImplementedError, "change_column is not implemented"
-
end
-
-
# Sets a new default value for a column.
-
#
-
# change_column_default(:suppliers, :qualification, 'new')
-
# change_column_default(:accounts, :authorized, 1)
-
# change_column_default(:users, :email, nil)
-
1
def change_column_default(table_name, column_name, default)
-
raise NotImplementedError, "change_column_default is not implemented"
-
end
-
-
# Renames a column.
-
#
-
# rename_column(:suppliers, :description, :name)
-
1
def rename_column(table_name, column_name, new_column_name)
-
raise NotImplementedError, "rename_column is not implemented"
-
end
-
-
# Adds a new index to the table. +column_name+ can be a single Symbol, or
-
# an Array of Symbols.
-
#
-
# The index will be named after the table and the column name(s), unless
-
# you pass <tt>:name</tt> as an option.
-
#
-
# ====== Creating a simple index
-
# add_index(:suppliers, :name)
-
# generates
-
# CREATE INDEX suppliers_name_index ON suppliers(name)
-
#
-
# ====== Creating a unique index
-
# add_index(:accounts, [:branch_id, :party_id], unique: true)
-
# generates
-
# CREATE UNIQUE INDEX accounts_branch_id_party_id_index ON accounts(branch_id, party_id)
-
#
-
# ====== Creating a named index
-
# add_index(:accounts, [:branch_id, :party_id], unique: true, name: 'by_branch_party')
-
# generates
-
# CREATE UNIQUE INDEX by_branch_party ON accounts(branch_id, party_id)
-
#
-
# ====== Creating an index with specific key length
-
# add_index(:accounts, :name, name: 'by_name', length: 10)
-
# generates
-
# CREATE INDEX by_name ON accounts(name(10))
-
#
-
# add_index(:accounts, [:name, :surname], name: 'by_name_surname', length: {name: 10, surname: 15})
-
# generates
-
# CREATE INDEX by_name_surname ON accounts(name(10), surname(15))
-
#
-
# Note: SQLite doesn't support index length
-
#
-
# ====== Creating an index with a sort order (desc or asc, asc is the default)
-
# add_index(:accounts, [:branch_id, :party_id, :surname], order: {branch_id: :desc, party_id: :asc})
-
# generates
-
# CREATE INDEX by_branch_desc_party ON accounts(branch_id DESC, party_id ASC, surname)
-
#
-
# Note: mysql doesn't yet support index order (it accepts the syntax but ignores it)
-
#
-
# ====== Creating a partial index
-
# add_index(:accounts, [:branch_id, :party_id], unique: true, where: "active")
-
# generates
-
# CREATE UNIQUE INDEX index_accounts_on_branch_id_and_party_id ON accounts(branch_id, party_id) WHERE active
-
#
-
# Note: only supported by PostgreSQL
-
#
-
1
def add_index(table_name, column_name, options = {})
-
74
index_name, index_type, index_columns, index_options = add_index_options(table_name, column_name, options)
-
71
execute "CREATE #{index_type} INDEX #{quote_column_name(index_name)} ON #{quote_table_name(table_name)} (#{index_columns})#{index_options}"
-
end
-
-
# Remove the given index from the table.
-
#
-
# Remove the index_accounts_on_column in the accounts table.
-
# remove_index :accounts, :column
-
# Remove the index named index_accounts_on_branch_id in the accounts table.
-
# remove_index :accounts, column: :branch_id
-
# Remove the index named index_accounts_on_branch_id_and_party_id in the accounts table.
-
# remove_index :accounts, column: [:branch_id, :party_id]
-
# Remove the index named by_branch_party in the accounts table.
-
# remove_index :accounts, name: :by_branch_party
-
1
def remove_index(table_name, options = {})
-
22
remove_index!(table_name, index_name_for_remove(table_name, options))
-
end
-
-
1
def remove_index!(table_name, index_name) #:nodoc:
-
execute "DROP INDEX #{quote_column_name(index_name)} ON #{quote_table_name(table_name)}"
-
end
-
-
# Rename an index.
-
#
-
# Rename the index_people_on_last_name index to index_users_on_last_name
-
# rename_index :people, 'index_people_on_last_name', 'index_users_on_last_name'
-
1
def rename_index(table_name, old_name, new_name)
-
# this is a naive implementation; some DBs may support this more efficiently (Postgres, for instance)
-
old_index_def = indexes(table_name).detect { |i| i.name == old_name }
-
return unless old_index_def
-
remove_index(table_name, :name => old_name)
-
add_index(table_name, old_index_def.columns, :name => new_name, :unique => old_index_def.unique)
-
end
-
-
1
def index_name(table_name, options) #:nodoc:
-
121
if Hash === options
-
108
if options[:column]
-
101
"index_#{table_name}_on_#{Array(options[:column]) * '_and_'}"
-
7
elsif options[:name]
-
7
options[:name]
-
else
-
raise ArgumentError, "You must specify the index name"
-
end
-
else
-
13
index_name(table_name, :column => options)
-
end
-
end
-
-
# Verify the existence of an index with a given name.
-
#
-
# The default argument is returned if the underlying implementation does not define the indexes method,
-
# as there's no way to determine the correct answer in that case.
-
1
def index_name_exists?(table_name, index_name, default)
-
97
return default unless respond_to?(:indexes)
-
97
index_name = index_name.to_s
-
131
indexes(table_name).detect { |i| i.name == index_name }
-
end
-
-
# Adds a reference. Optionally adds a +type+ column, if <tt>:polymorphic</tt> option is provided.
-
# <tt>add_reference</tt> and <tt>add_belongs_to</tt> are acceptable.
-
#
-
# ====== Create a user_id column
-
# add_reference(:products, :user)
-
#
-
# ====== Create a supplier_id and supplier_type columns
-
# add_belongs_to(:products, :supplier, polymorphic: true)
-
#
-
# ====== Create a supplier_id, supplier_type columns and appropriate index
-
# add_reference(:products, :supplier, polymorphic: true, index: true)
-
#
-
1
def add_reference(table_name, ref_name, options = {})
-
13
polymorphic = options.delete(:polymorphic)
-
13
index_options = options.delete(:index)
-
13
add_column(table_name, "#{ref_name}_id", :integer, options)
-
13
add_column(table_name, "#{ref_name}_type", :string, polymorphic.is_a?(Hash) ? polymorphic : options) if polymorphic
-
19
add_index(table_name, polymorphic ? %w[id type].map{ |t| "#{ref_name}_#{t}" } : "#{ref_name}_id", index_options.is_a?(Hash) ? index_options : nil) if index_options
-
end
-
1
alias :add_belongs_to :add_reference
-
-
# Removes the reference(s). Also removes a +type+ column if one exists.
-
# <tt>remove_reference</tt>, <tt>remove_references</tt> and <tt>remove_belongs_to</tt> are acceptable.
-
#
-
# ====== Remove the reference
-
# remove_reference(:products, :user, index: true)
-
#
-
# ====== Remove polymorphic reference
-
# remove_reference(:products, :supplier, polymorphic: true)
-
#
-
1
def remove_reference(table_name, ref_name, options = {})
-
6
remove_column(table_name, "#{ref_name}_id")
-
6
remove_column(table_name, "#{ref_name}_type") if options[:polymorphic]
-
end
-
1
alias :remove_belongs_to :remove_reference
-
-
# Returns a string of <tt>CREATE TABLE</tt> SQL statement(s) for recreating the
-
# entire structure of the database.
-
1
def structure_dump
-
end
-
-
1
def dump_schema_information #:nodoc:
-
1
sm_table = ActiveRecord::Migrator.schema_migrations_table_name
-
-
1
ActiveRecord::SchemaMigration.order('version').map { |sm|
-
3
"INSERT INTO #{sm_table} (version) VALUES ('#{sm.version}');"
-
}.join "\n\n"
-
end
-
-
# Should not be called normally, but this operation is non-destructive.
-
# The migrations module handles this automatically.
-
1
def initialize_schema_migrations_table
-
19
ActiveRecord::SchemaMigration.create_table
-
end
-
-
1
def assume_migrated_upto_version(version, migrations_paths = ActiveRecord::Migrator.migrations_paths)
-
2
migrations_paths = Array(migrations_paths)
-
2
version = version.to_i
-
2
sm_table = quote_table_name(ActiveRecord::Migrator.schema_migrations_table_name)
-
-
3
migrated = select_values("SELECT version FROM #{sm_table}").map { |v| v.to_i }
-
4
paths = migrations_paths.map {|p| "#{p}/[0-9]*_*.rb" }
-
2
versions = Dir[*paths].map do |filename|
-
filename.split('/').last.split('_').first.to_i
-
end
-
-
2
unless migrated.include?(version)
-
2
execute "INSERT INTO #{sm_table} (version) VALUES ('#{version}')"
-
end
-
-
2
inserted = Set.new
-
2
(versions - migrated).each do |v|
-
if inserted.include?(v)
-
raise "Duplicate migration #{v}. Please renumber your migrations to resolve the conflict."
-
elsif v < version
-
execute "INSERT INTO #{sm_table} (version) VALUES ('#{v}')"
-
inserted << v
-
end
-
end
-
end
-
-
1
def type_to_sql(type, limit = nil, precision = nil, scale = nil) #:nodoc:
-
984
if native = native_database_types[type.to_sym]
-
984
column_type_sql = (native.is_a?(Hash) ? native[:name] : native).dup
-
-
984
if type == :decimal # ignore limit, use precision and scale
-
16
scale ||= native[:scale]
-
-
16
if precision ||= native[:precision]
-
15
if scale
-
13
column_type_sql << "(#{precision},#{scale})"
-
else
-
2
column_type_sql << "(#{precision})"
-
end
-
elsif scale
-
raise ArgumentError, "Error adding decimal column: precision cannot be empty if scale if specified"
-
end
-
-
968
elsif (type != :primary_key) && (limit ||= native.is_a?(Hash) && native[:limit])
-
358
column_type_sql << "(#{limit})"
-
end
-
-
984
column_type_sql
-
else
-
type
-
end
-
end
-
-
1
def add_column_options!(sql, options) #:nodoc:
-
895
sql << " DEFAULT #{quote(options[:default], options[:column])}" if options_include_default?(options)
-
# must explicitly check for :null to allow change_column to work on migrations
-
895
if options[:null] == false
-
72
sql << " NOT NULL"
-
end
-
end
-
-
# SELECT DISTINCT clause for a given set of columns and a given ORDER BY clause.
-
# Both PostgreSQL and Oracle overrides this for custom DISTINCT syntax.
-
#
-
# distinct("posts.id", "posts.created_at desc")
-
1
def distinct(columns, order_by)
-
"DISTINCT #{columns}"
-
end
-
-
# Adds timestamps (created_at and updated_at) columns to the named table.
-
#
-
# add_timestamps(:suppliers)
-
1
def add_timestamps(table_name)
-
add_column table_name, :created_at, :datetime
-
add_column table_name, :updated_at, :datetime
-
end
-
-
# Removes the timestamp columns (created_at and updated_at) from the table definition.
-
#
-
# remove_timestamps(:suppliers)
-
1
def remove_timestamps(table_name)
-
remove_column table_name, :updated_at
-
remove_column table_name, :created_at
-
end
-
-
1
protected
-
1
def add_index_sort_order(option_strings, column_names, options = {})
-
71
if options.is_a?(Hash) && order = options[:order]
-
4
case order
-
when Hash
-
8
column_names.each {|name| option_strings[name] += " #{order[name].upcase}" if order.has_key?(name)}
-
when String
-
column_names.each {|name| option_strings[name] += " #{order.upcase}"}
-
end
-
end
-
-
71
return option_strings
-
end
-
-
# Overridden by the mysql adapter for supporting index lengths
-
1
def quoted_columns_for_index(column_names, options = {})
-
170
option_strings = Hash[column_names.map {|name| [name, '']}]
-
-
# add index sort order if supported
-
71
if supports_index_sort_order?
-
71
option_strings = add_index_sort_order(option_strings, column_names, options)
-
end
-
-
170
column_names.map {|name| quote_column_name(name) + option_strings[name]}
-
end
-
-
1
def options_include_default?(options)
-
910
options.include?(:default) && !(options[:null] == false && options[:default].nil?)
-
end
-
-
1
def add_index_options(table_name, column_name, options = {})
-
74
column_names = Array(column_name)
-
74
index_name = index_name(table_name, column: column_names)
-
-
74
if Hash === options # legacy support, since this param was a string
-
66
options.assert_valid_keys(:unique, :order, :name, :where, :length)
-
-
65
index_type = options[:unique] ? "UNIQUE" : ""
-
65
index_name = options[:name].to_s if options.key?(:name)
-
-
65
if supports_partial_index?
-
65
index_options = options[:where] ? " WHERE #{options[:where]}" : ""
-
end
-
else
-
8
if options
-
1
message = "Passing a string as third argument of `add_index` is deprecated and will" +
-
" be removed in Rails 4.1." +
-
" Use add_index(#{table_name.inspect}, #{column_name.inspect}, unique: true) instead"
-
-
1
ActiveSupport::Deprecation.warn message
-
end
-
-
8
index_type = options
-
end
-
-
73
if index_name.length > index_name_length
-
1
raise ArgumentError, "Index name '#{index_name}' on table '#{table_name}' is too long; the limit is #{index_name_length} characters"
-
end
-
72
if index_name_exists?(table_name, index_name, false)
-
1
raise ArgumentError, "Index name '#{index_name}' on table '#{table_name}' already exists"
-
end
-
71
index_columns = quoted_columns_for_index(column_names, options).join(", ")
-
-
71
[index_name, index_type, index_columns, index_options]
-
end
-
-
1
def index_name_for_remove(table_name, options = {})
-
22
index_name = index_name(table_name, options)
-
-
22
unless index_name_exists?(table_name, index_name, true)
-
1
raise ArgumentError, "Index name '#{index_name}' on table '#{table_name}' does not exist"
-
end
-
-
21
index_name
-
end
-
-
1
def columns_for_remove(table_name, *column_names)
-
257
raise ArgumentError.new("You must specify at least one column name. Example: remove_column(:people, :first_name)") if column_names.blank?
-
512
column_names.map {|column_name| quote_column_name(column_name) }
-
end
-
-
1
private
-
1
def table_definition
-
TableDefinition.new(self)
-
end
-
end
-
end
-
end
-
1
module ActiveRecord
-
1
module ConnectionAdapters
-
1
class Transaction #:nodoc:
-
1
attr_reader :connection
-
-
1
def initialize(connection)
-
19881
@connection = connection
-
end
-
end
-
-
1
class ClosedTransaction < Transaction #:nodoc:
-
1
def number
-
5657
0
-
end
-
-
1
def begin(options = {})
-
16858
RealTransaction.new(connection, self, options)
-
end
-
-
1
def closed?
-
2550
true
-
end
-
-
1
def open?
-
3
false
-
end
-
-
1
def joinable?
-
218
false
-
end
-
-
# This is a noop when there are no open transactions
-
1
def add_record(record)
-
end
-
end
-
-
1
class OpenTransaction < Transaction #:nodoc:
-
1
attr_reader :parent, :records
-
1
attr_writer :joinable
-
-
1
def initialize(connection, parent, options = {})
-
19685
super connection
-
-
19685
@parent = parent
-
19685
@records = []
-
19685
@finishing = false
-
19685
@joinable = options.fetch(:joinable, true)
-
end
-
-
# This state is necesarry so that we correctly handle stuff that might
-
# happen in a commit/rollback. But it's kinda distasteful. Maybe we can
-
# find a better way to structure it in the future.
-
1
def finishing?
-
12590
@finishing
-
end
-
-
1
def joinable?
-
4081
@joinable && !finishing?
-
end
-
-
1
def number
-
8493
if finishing?
-
2827
parent.number
-
else
-
5666
parent.number + 1
-
end
-
end
-
-
1
def begin(options = {})
-
2829
if finishing?
-
1
parent.begin
-
else
-
2828
SavepointTransaction.new(connection, self, options)
-
end
-
end
-
-
1
def rollback
-
16651
@finishing = true
-
16651
perform_rollback
-
16651
parent
-
end
-
-
1
def commit
-
3034
@finishing = true
-
3034
perform_commit
-
3031
parent
-
end
-
-
1
def add_record(record)
-
6443
records << record
-
end
-
-
1
def rollback_records
-
16651
records.uniq.each do |record|
-
2732
begin
-
2732
record.rolledback!(parent.closed?)
-
rescue => e
-
1
record.logger.error(e) if record.respond_to?(:logger) && record.logger
-
end
-
end
-
end
-
-
1
def commit_records
-
419
records.uniq.each do |record|
-
145
begin
-
145
record.committed!
-
rescue => e
-
1
record.logger.error(e) if record.respond_to?(:logger) && record.logger
-
end
-
end
-
end
-
-
1
def closed?
-
182
false
-
end
-
-
1
def open?
-
16390
true
-
end
-
end
-
-
1
class RealTransaction < OpenTransaction #:nodoc:
-
1
def initialize(connection, parent, options = {})
-
16858
super
-
-
16858
if options[:isolation]
-
4
connection.begin_isolated_db_transaction(options[:isolation])
-
else
-
16854
connection.begin_db_transaction
-
end
-
end
-
-
1
def perform_rollback
-
16436
connection.rollback_db_transaction
-
16436
rollback_records
-
end
-
-
1
def perform_commit
-
422
connection.commit_db_transaction
-
419
commit_records
-
end
-
end
-
-
1
class SavepointTransaction < OpenTransaction #:nodoc:
-
1
def initialize(connection, parent, options = {})
-
2828
if options[:isolation]
-
1
raise ActiveRecord::TransactionIsolationError, "cannot set transaction isolation in a nested transaction"
-
end
-
-
2827
super
-
2827
connection.create_savepoint
-
end
-
-
1
def perform_rollback
-
215
connection.rollback_to_savepoint
-
215
rollback_records
-
end
-
-
1
def perform_commit
-
2612
connection.release_savepoint
-
5625
records.each { |r| parent.add_record(r) }
-
end
-
end
-
end
-
end
-
1
require 'date'
-
1
require 'bigdecimal'
-
1
require 'bigdecimal/util'
-
1
require 'active_support/core_ext/benchmark'
-
1
require 'active_record/connection_adapters/schema_cache'
-
1
require 'active_record/connection_adapters/abstract/schema_dumper'
-
1
require 'monitor'
-
1
require 'active_support/deprecation'
-
-
1
module ActiveRecord
-
1
module ConnectionAdapters # :nodoc:
-
1
extend ActiveSupport::Autoload
-
-
1
autoload :Column
-
1
autoload :ConnectionSpecification
-
-
1
autoload_at 'active_record/connection_adapters/abstract/schema_definitions' do
-
1
autoload :IndexDefinition
-
1
autoload :ColumnDefinition
-
1
autoload :TableDefinition
-
1
autoload :Table
-
end
-
-
1
autoload_at 'active_record/connection_adapters/abstract/connection_pool' do
-
1
autoload :ConnectionHandler
-
1
autoload :ConnectionManagement
-
end
-
-
1
autoload_under 'abstract' do
-
1
autoload :SchemaStatements
-
1
autoload :DatabaseStatements
-
1
autoload :DatabaseLimits
-
1
autoload :Quoting
-
1
autoload :ConnectionPool
-
1
autoload :QueryCache
-
end
-
-
1
autoload_at 'active_record/connection_adapters/abstract/transaction' do
-
1
autoload :ClosedTransaction
-
1
autoload :RealTransaction
-
1
autoload :SavepointTransaction
-
end
-
-
# Active Record supports multiple database systems. AbstractAdapter and
-
# related classes form the abstraction layer which makes this possible.
-
# An AbstractAdapter represents a connection to a database, and provides an
-
# abstract interface for database-specific functionality such as establishing
-
# a connection, escaping values, building the right SQL fragments for ':offset'
-
# and ':limit' options, etc.
-
#
-
# All the concrete database adapters follow the interface laid down in this class.
-
# ActiveRecord::Base.connection returns an AbstractAdapter object, which
-
# you can use.
-
#
-
# Most of the methods in the adapter are useful during migrations. Most
-
# notably, the instance methods provided by SchemaStatement are very useful.
-
1
class AbstractAdapter
-
1
include Quoting, DatabaseStatements, SchemaStatements
-
1
include DatabaseLimits
-
1
include QueryCache
-
1
include ActiveSupport::Callbacks
-
1
include MonitorMixin
-
1
include ColumnDumper
-
-
1
define_callbacks :checkout, :checkin
-
-
1
attr_accessor :visitor, :pool
-
1
attr_reader :schema_cache, :last_use, :in_use, :logger
-
1
alias :in_use? :in_use
-
-
1
def initialize(connection, logger = nil, pool = nil) #:nodoc:
-
113
super()
-
-
113
@connection = connection
-
113
@in_use = false
-
113
@instrumenter = ActiveSupport::Notifications.instrumenter
-
113
@last_use = false
-
113
@logger = logger
-
113
@pool = pool
-
135
@query_cache = Hash.new { |h,sql| h[sql] = {} }
-
113
@query_cache_enabled = false
-
113
@schema_cache = SchemaCache.new self
-
113
@visitor = nil
-
end
-
-
1
def lease
-
16812
synchronize do
-
16812
unless in_use
-
16811
@in_use = true
-
16811
@last_use = Time.now
-
end
-
end
-
end
-
-
1
def schema_cache=(cache)
-
cache.connection = self
-
@schema_cache = cache
-
end
-
-
1
def expire
-
16829
@in_use = false
-
end
-
-
# Returns the human-readable name of the adapter. Use mixed case - one
-
# can always use downcase if needed.
-
1
def adapter_name
-
'Abstract'
-
end
-
-
# Does this adapter support migrations? Backend specific, as the
-
# abstract adapter always returns +false+.
-
1
def supports_migrations?
-
false
-
end
-
-
# Can this adapter determine the primary key for tables not attached
-
# to an Active Record class, such as join tables? Backend specific, as
-
# the abstract adapter always returns +false+.
-
1
def supports_primary_key?
-
false
-
end
-
-
# Does this adapter support using DISTINCT within COUNT? This is +true+
-
# for all adapters except sqlite.
-
1
def supports_count_distinct?
-
true
-
end
-
-
# Does this adapter support DDL rollbacks in transactions? That is, would
-
# CREATE TABLE or ALTER TABLE get rolled back by a transaction? PostgreSQL,
-
# SQL Server, and others support this. MySQL and others do not.
-
1
def supports_ddl_transactions?
-
false
-
end
-
-
1
def supports_bulk_alter?
-
6
false
-
end
-
-
# Does this adapter support savepoints? PostgreSQL and MySQL do,
-
# SQLite < 3.6.8 does not.
-
1
def supports_savepoints?
-
false
-
end
-
-
# Should primary key values be selected from their corresponding
-
# sequence before the insert statement? If true, next_sequence_value
-
# is called before each insert to set the record's primary key.
-
# This is false for all adapters but Firebird.
-
1
def prefetch_primary_key?(table_name = nil)
-
2253
false
-
end
-
-
# Does this adapter support index sort order?
-
1
def supports_index_sort_order?
-
false
-
end
-
-
# Does this adapter support partial indices?
-
1
def supports_partial_index?
-
false
-
end
-
-
# Does this adapter support explain? As of this writing sqlite3,
-
# mysql2, and postgresql are the only ones that do.
-
1
def supports_explain?
-
false
-
end
-
-
# Does this adapter support setting the isolation level for a transaction?
-
1
def supports_transaction_isolation?
-
false
-
end
-
-
# QUOTING ==================================================
-
-
# Returns a bind substitution value given a +column+ and list of current
-
# +binds+
-
1
def substitute_at(column, index)
-
Arel::Nodes::BindParam.new '?'
-
end
-
-
# REFERENTIAL INTEGRITY ====================================
-
-
# Override to turn off referential integrity while executing <tt>&block</tt>.
-
1
def disable_referential_integrity
-
yield
-
end
-
-
# CONNECTION MANAGEMENT ====================================
-
-
# Checks whether the connection to the database is still active. This includes
-
# checking whether the database is actually capable of responding, i.e. whether
-
# the connection isn't stale.
-
1
def active?
-
end
-
-
# Disconnects from the database if already connected, and establishes a
-
# new connection with the database. Implementors should call super if they
-
# override the default implementation.
-
1
def reconnect!
-
8
clear_cache!
-
8
reset_transaction
-
end
-
-
# Disconnects from the database if already connected. Otherwise, this
-
# method does nothing.
-
1
def disconnect!
-
75
clear_cache!
-
75
reset_transaction
-
end
-
-
# Reset the state of this connection, directing the DBMS to clear
-
# transactions and other connection-related server-side state. Usually a
-
# database-dependent operation.
-
#
-
# The default implementation does nothing; the implementation should be
-
# overridden by concrete adapters.
-
1
def reset!
-
# this should be overridden by concrete adapters
-
end
-
-
###
-
# Clear any caching the database adapter may be doing, for example
-
# clearing the prepared statement cache. This is database specific.
-
1
def clear_cache!
-
# this should be overridden by concrete adapters
-
end
-
-
# Returns true if its required to reload the connection between requests for development mode.
-
# This is not the case for Ruby/MySQL and it's not necessary for any adapters except SQLite.
-
1
def requires_reloading?
-
26
false
-
end
-
-
# Checks whether the connection to the database is still active (i.e. not stale).
-
# This is done under the hood by calling <tt>active?</tt>. If the connection
-
# is no longer active, then this method will reconnect to the database.
-
1
def verify!(*ignored)
-
16808
reconnect! unless active?
-
end
-
-
# Provides access to the underlying database driver for this adapter. For
-
# example, this method returns a Mysql object in case of MysqlAdapter,
-
# and a PGconn object in case of PostgreSQLAdapter.
-
#
-
# This is useful for when you need to call a proprietary method such as
-
# PostgreSQL's lo_* methods.
-
1
def raw_connection
-
1
@connection
-
end
-
-
1
def open_transactions
-
5657
@transaction.number
-
end
-
-
1
def increment_open_transactions
-
ActiveSupport::Deprecation.warn "#increment_open_transactions is deprecated and has no effect"
-
end
-
-
1
def decrement_open_transactions
-
ActiveSupport::Deprecation.warn "#decrement_open_transactions is deprecated and has no effect"
-
end
-
-
1
def transaction_joinable=(joinable)
-
1
message = "#transaction_joinable= is deprecated. Please pass the :joinable option to #begin_transaction instead."
-
1
ActiveSupport::Deprecation.warn message
-
1
@transaction.joinable = joinable
-
end
-
-
1
def create_savepoint
-
end
-
-
1
def rollback_to_savepoint
-
end
-
-
1
def release_savepoint
-
end
-
-
1
def case_sensitive_modifier(node)
-
100
node
-
end
-
-
1
def case_insensitive_comparison(table, attribute, column, value)
-
14
table[attribute].lower.eq(table.lower(value))
-
end
-
-
1
def current_savepoint_name
-
5654
"active_record_#{open_transactions}"
-
end
-
-
# Check the connection back in to the connection pool
-
1
def close
-
22
pool.checkin self
-
end
-
-
1
protected
-
-
1
def log(sql, name = "SQL", binds = [])
-
67840
@instrumenter.instrument(
-
"sql.active_record",
-
:sql => sql,
-
:name => name,
-
:connection_id => object_id,
-
67840
:binds => binds) { yield }
-
rescue => e
-
442
message = "#{e.class.name}: #{e.message}: #{sql}"
-
442
@logger.error message if @logger
-
442
exception = translate_exception(e, message)
-
442
exception.set_backtrace e.backtrace
-
442
raise exception
-
end
-
-
1
def translate_exception(exception, message)
-
# override in derived class
-
439
ActiveRecord::StatementInvalid.new(message)
-
end
-
end
-
end
-
end
-
1
require 'set'
-
-
1
module ActiveRecord
-
# :stopdoc:
-
1
module ConnectionAdapters
-
# An abstract definition of a column in a table.
-
1
class Column
-
1
TRUE_VALUES = [true, 1, '1', 't', 'T', 'true', 'TRUE', 'on', 'ON'].to_set
-
1
FALSE_VALUES = [false, 0, '0', 'f', 'F', 'false', 'FALSE', 'off', 'OFF'].to_set
-
-
1
module Format
-
1
ISO_DATE = /\A(\d{4})-(\d\d)-(\d\d)\z/
-
1
ISO_DATETIME = /\A(\d{4})-(\d\d)-(\d\d) (\d\d):(\d\d):(\d\d)(\.\d+)?\z/
-
end
-
-
1
attr_reader :name, :default, :type, :limit, :null, :sql_type, :precision, :scale
-
1
attr_accessor :primary, :coder
-
-
1
alias :encoded? :coder
-
-
# Instantiates a new column in the table.
-
#
-
# +name+ is the column's name, such as <tt>supplier_id</tt> in <tt>supplier_id int(11)</tt>.
-
# +default+ is the type-casted default value, such as +new+ in <tt>sales_stage varchar(20) default 'new'</tt>.
-
# +sql_type+ is used to extract the column's length, if necessary. For example +60+ in
-
# <tt>company_name varchar(60)</tt>.
-
# It will be mapped to one of the standard Rails SQL types in the <tt>type</tt> attribute.
-
# +null+ determines if this column allows +NULL+ values.
-
1
def initialize(name, default, sql_type = nil, null = true)
-
53568
@name = name
-
53568
@sql_type = sql_type
-
53568
@null = null
-
53568
@limit = extract_limit(sql_type)
-
53568
@precision = extract_precision(sql_type)
-
53568
@scale = extract_scale(sql_type)
-
53568
@type = simplified_type(sql_type)
-
53568
@default = extract_default(default)
-
53568
@primary = nil
-
53568
@coder = nil
-
end
-
-
# Returns +true+ if the column is either of type string or text.
-
1
def text?
-
135
type == :string || type == :text
-
end
-
-
# Returns +true+ if the column is either of type integer, float or decimal.
-
1
def number?
-
29275
type == :integer || type == :float || type == :decimal
-
end
-
-
1
def has_default?
-
9922
!default.nil?
-
end
-
-
# Returns the Ruby class that corresponds to the abstract data type.
-
1
def klass
-
35
case type
-
when :integer then Fixnum
-
when :float then Float
-
when :decimal then BigDecimal
-
21
when :datetime, :timestamp, :time then Time
-
14
when :date then Date
-
when :text, :string, :binary then String
-
when :boolean then Object
-
end
-
end
-
-
1
def binary?
-
14577
type == :binary
-
end
-
-
# Casts a Ruby value to something appropriate for writing to the database.
-
1
def type_cast_for_write(value)
-
14442
return value unless number?
-
-
7685
if value == false
-
0
-
7685
elsif value == true
-
1
-
7685
elsif value.is_a?(String) && value.blank?
-
nil
-
else
-
7679
value
-
end
-
end
-
-
# Casts value (which is a String) to an appropriate instance.
-
1
def type_cast(value)
-
753
return nil if value.nil?
-
359
return coder.load(value) if encoded?
-
-
358
klass = self.class
-
-
358
case type
-
98
when :string, :text then value
-
73
when :integer then klass.value_to_integer(value)
-
2
when :float then value.to_f
-
when :decimal then klass.value_to_decimal(value)
-
65
when :datetime, :timestamp then klass.string_to_time(value)
-
3
when :time then klass.string_to_dummy_time(value)
-
3
when :date then klass.value_to_date(value)
-
31
when :binary then klass.binary_to_string(value)
-
81
when :boolean then klass.value_to_boolean(value)
-
2
else value
-
end
-
end
-
-
1
def type_cast_code(var_name)
-
message = "Column#type_cast_code is deprecated in favor of using Column#type_cast only, " \
-
"and it is going to be removed in future Rails versions."
-
ActiveSupport::Deprecation.warn message
-
-
klass = self.class.name
-
-
case type
-
when :string, :text then var_name
-
when :integer then "#{klass}.value_to_integer(#{var_name})"
-
when :float then "#{var_name}.to_f"
-
when :decimal then "#{klass}.value_to_decimal(#{var_name})"
-
when :datetime, :timestamp then "#{klass}.string_to_time(#{var_name})"
-
when :time then "#{klass}.string_to_dummy_time(#{var_name})"
-
when :date then "#{klass}.value_to_date(#{var_name})"
-
when :binary then "#{klass}.binary_to_string(#{var_name})"
-
when :boolean then "#{klass}.value_to_boolean(#{var_name})"
-
when :hstore then "#{klass}.string_to_hstore(#{var_name})"
-
when :inet, :cidr then "#{klass}.string_to_cidr(#{var_name})"
-
when :json then "#{klass}.string_to_json(#{var_name})"
-
else var_name
-
end
-
end
-
-
# Returns the human name of the column name.
-
#
-
# ===== Examples
-
# Column.new('sales_stage', ...).human_name # => 'Sales stage'
-
1
def human_name
-
1
Base.human_attribute_name(@name)
-
end
-
-
1
def extract_default(default)
-
53568
type_cast(default)
-
end
-
-
# Used to convert from Strings to BLOBs
-
1
def string_to_binary(value)
-
2
self.class.string_to_binary(value)
-
end
-
-
1
class << self
-
# Used to convert from Strings to BLOBs
-
1
def string_to_binary(value)
-
2
value
-
end
-
-
# Used to convert from BLOBs to Strings
-
1
def binary_to_string(value)
-
31
value
-
end
-
-
1
def value_to_date(value)
-
153
if value.is_a?(String)
-
129
return nil if value.blank?
-
125
fast_string_to_date(value) || fallback_string_to_date(value)
-
24
elsif value.respond_to?(:to_date)
-
24
value.to_date
-
else
-
value
-
end
-
end
-
-
1
def string_to_time(string)
-
1151
return string unless string.is_a?(String)
-
1093
return nil if string.blank?
-
-
1085
fast_string_to_time(string) || fallback_string_to_time(string)
-
end
-
-
1
def string_to_dummy_time(string)
-
109
return string unless string.is_a?(String)
-
101
return nil if string.blank?
-
-
97
dummy_time_string = "2000-01-01 #{string}"
-
-
fast_string_to_time(dummy_time_string) || begin
-
10
time_hash = Date._parse(dummy_time_string)
-
10
return nil if time_hash[:hour].nil?
-
8
new_time(*time_hash.values_at(:year, :mon, :mday, :hour, :min, :sec, :sec_fraction))
-
97
end
-
end
-
-
# convert something to a boolean
-
1
def value_to_boolean(value)
-
2130
if value.is_a?(String) && value.blank?
-
nil
-
else
-
2122
TRUE_VALUES.include?(value)
-
end
-
end
-
-
# Used to convert values to integer.
-
# handle the case when an integer column is used to store boolean values
-
1
def value_to_integer(value)
-
73
case value
-
when TrueClass, FalseClass
-
2
value ? 1 : 0
-
else
-
71
value.to_i
-
end
-
end
-
-
# convert something to a BigDecimal
-
1
def value_to_decimal(value)
-
# Using .class is faster than .is_a? and
-
# subclasses of BigDecimal will be handled
-
# in the else clause
-
100
if value.class == BigDecimal
-
22
value
-
78
elsif value.respond_to?(:to_d)
-
78
value.to_d
-
else
-
value.to_s.to_d
-
end
-
end
-
-
1
protected
-
# '0.123456' -> 123456
-
# '1.123456' -> 123456
-
1
def microseconds(time)
-
64
time[:sec_fraction] ? (time[:sec_fraction] * 1_000_000).to_i : 0
-
end
-
-
1
def new_date(year, mon, mday)
-
125
if year && year != 0
-
125
Date.new(year, mon, mday) rescue nil
-
end
-
end
-
-
1
def new_time(year, mon, mday, hour, min, sec, microsec)
-
# Treat 0000-00-00 00:00:00 as nil.
-
1180
return nil if year.nil? || (year == 0 && mon == 0 && mday == 0)
-
-
1178
Time.time_with_datetime_fallback(Base.default_timezone, year, mon, mday, hour, min, sec, microsec) rescue nil
-
end
-
-
1
def fast_string_to_date(string)
-
125
if string =~ Format::ISO_DATE
-
125
new_date $1.to_i, $2.to_i, $3.to_i
-
end
-
end
-
-
# Doesn't handle time zones.
-
1
def fast_string_to_time(string)
-
1182
if string =~ Format::ISO_DATETIME
-
1108
microsec = ($7.to_r * 1_000_000).to_i
-
1108
new_time $1.to_i, $2.to_i, $3.to_i, $4.to_i, $5.to_i, $6.to_i, microsec
-
end
-
end
-
-
1
def fallback_string_to_date(string)
-
new_date(*::Date._parse(string, false).values_at(:year, :mon, :mday))
-
end
-
-
1
def fallback_string_to_time(string)
-
64
time_hash = Date._parse(string)
-
64
time_hash[:sec_fraction] = microseconds(time_hash)
-
-
64
new_time(*time_hash.values_at(:year, :mon, :mday, :hour, :min, :sec, :sec_fraction))
-
end
-
end
-
-
1
private
-
1
def extract_limit(sql_type)
-
47469
$1.to_i if sql_type =~ /\((.*)\)/
-
end
-
-
1
def extract_precision(sql_type)
-
47603
$2.to_i if sql_type =~ /^(numeric|decimal|number)\((\d+)(,\d+)?\)/i
-
end
-
-
1
def extract_scale(sql_type)
-
53756
case sql_type
-
when /^(numeric|decimal|number)\((\d+)\)/i then 0
-
426
when /^(numeric|decimal|number)\((\d+)(,(\d+))\)/i then $4.to_i
-
end
-
end
-
-
1
def simplified_type(field_type)
-
32311
case field_type
-
when /int/i
-
27472
:integer
-
when /float|double/i
-
2
:float
-
when /decimal|numeric|number/i
-
214
extract_scale(field_type) == 0 ? :integer : :decimal
-
when /datetime/i
-
3
:datetime
-
when /timestamp/i
-
13
:timestamp
-
when /time/i
-
594
:time
-
when /date/i
-
738
:date
-
when /clob/i, /text/i
-
2295
:text
-
when /blob/i, /binary/i
-
2
:binary
-
when /char/i, /string/i
-
38
:string
-
when /boolean/i
-
938
:boolean
-
end
-
end
-
end
-
end
-
# :startdoc:
-
end
-
1
require 'uri'
-
-
1
module ActiveRecord
-
1
module ConnectionAdapters
-
1
class ConnectionSpecification #:nodoc:
-
1
attr_reader :config, :adapter_method
-
-
1
def initialize(config, adapter_method)
-
27
@config, @adapter_method = config, adapter_method
-
end
-
-
1
def initialize_dup(original)
-
3
@config = original.config.dup
-
end
-
-
##
-
# Builds a ConnectionSpecification from user input
-
1
class Resolver # :nodoc:
-
1
attr_reader :config, :klass, :configurations
-
-
1
def initialize(config, configurations)
-
25
@config = config
-
25
@configurations = configurations
-
end
-
-
1
def spec
-
25
case config
-
when nil
-
raise AdapterNotSpecified unless defined?(Rails.env)
-
resolve_string_connection Rails.env
-
when Symbol, String
-
17
resolve_string_connection config.to_s
-
when Hash
-
8
resolve_hash_connection config
-
end
-
end
-
-
1
private
-
1
def resolve_string_connection(spec) # :nodoc:
-
17
hash = configurations.fetch(spec) do |k|
-
connection_url_to_hash(k)
-
end
-
-
17
raise(AdapterNotSpecified, "#{spec} database is not configured") unless hash
-
-
17
resolve_hash_connection hash
-
end
-
-
1
def resolve_hash_connection(spec) # :nodoc:
-
25
spec = spec.symbolize_keys
-
-
25
raise(AdapterNotSpecified, "database configuration does not specify adapter") unless spec.key?(:adapter)
-
-
25
begin
-
25
require "active_record/connection_adapters/#{spec[:adapter]}_adapter"
-
rescue LoadError => e
-
raise LoadError, "Please install the #{spec[:adapter]} adapter: `gem install activerecord-#{spec[:adapter]}-adapter` (#{e.message})", e.backtrace
-
end
-
-
25
adapter_method = "#{spec[:adapter]}_connection"
-
-
25
ConnectionSpecification.new(spec, adapter_method)
-
end
-
-
1
def connection_url_to_hash(url) # :nodoc:
-
config = URI.parse url
-
adapter = config.scheme
-
adapter = "postgresql" if adapter == "postgres"
-
spec = { :adapter => adapter,
-
:username => config.user,
-
:password => config.password,
-
:port => config.port,
-
:database => config.path.sub(%r{^/},""),
-
:host => config.host }
-
spec.reject!{ |_,value| value.blank? }
-
uri_parser = URI::Parser.new
-
spec.map { |key,value| spec[key] = uri_parser.unescape(value) if value.is_a?(String) }
-
if config.query
-
options = Hash[config.query.split("&").map{ |pair| pair.split("=") }].symbolize_keys
-
spec.merge!(options)
-
end
-
spec
-
end
-
end
-
end
-
end
-
end
-
1
module ActiveRecord
-
1
module ConnectionAdapters
-
1
class PostgreSQLColumn < Column
-
1
module ArrayParser
-
1
private
-
# Loads pg_array_parser if available. String parsing can be
-
# performed quicker by a native extension, which will not create
-
# a large amount of Ruby objects that will need to be garbage
-
# collected. pg_array_parser has a C and Java extension
-
1
begin
-
1
require 'pg_array_parser'
-
include PgArrayParser
-
rescue LoadError
-
1
def parse_pg_array(string)
-
30
parse_data(string, 0)
-
end
-
end
-
-
1
def parse_data(string, index)
-
30
local_index = index
-
30
array = []
-
90
while(local_index < string.length)
-
30
case string[local_index]
-
when '{'
-
30
local_index,array = parse_array_contents(array, string, local_index + 1)
-
when '}'
-
return array
-
end
-
30
local_index += 1
-
end
-
-
30
array
-
end
-
-
1
def parse_array_contents(array, string, index)
-
34
is_escaping = false
-
34
is_quoted = false
-
34
was_quoted = false
-
34
current_item = ''
-
-
34
local_index = index
-
34
while local_index
-
508
token = string[local_index]
-
508
if is_escaping
-
4
current_item << token
-
4
is_escaping = false
-
else
-
504
if is_quoted
-
154
case token
-
when '"'
-
16
is_quoted = false
-
16
was_quoted = true
-
when "\\"
-
4
is_escaping = true
-
else
-
134
current_item << token
-
end
-
else
-
350
case token
-
when "\\"
-
is_escaping = true
-
when ','
-
58
add_item_to_array(array, current_item, was_quoted)
-
58
current_item = ''
-
58
was_quoted = false
-
when '"'
-
16
is_quoted = true
-
when '{'
-
4
internal_items = []
-
4
local_index,internal_items = parse_array_contents(internal_items, string, local_index + 1)
-
4
array.push(internal_items)
-
when '}'
-
34
add_item_to_array(array, current_item, was_quoted)
-
34
return local_index,array
-
else
-
238
current_item << token
-
end
-
end
-
end
-
-
474
local_index += 1
-
end
-
return local_index,array
-
end
-
-
1
def add_item_to_array(array, current_item, quoted)
-
92
if current_item.length == 0
-
87
elsif !quoted && current_item == 'NULL'
-
5
array.push nil
-
else
-
82
array.push current_item
-
end
-
end
-
end
-
end
-
end
-
end
-
1
module ActiveRecord
-
1
module ConnectionAdapters
-
1
class PostgreSQLColumn < Column
-
1
module Cast
-
1
def string_to_time(string)
-
5890
return string unless String === string
-
-
1088
case string
-
1
when 'infinity'; 1.0 / 0.0
-
1
when '-infinity'; -1.0 / 0.0
-
else
-
1086
super
-
end
-
end
-
-
1
def hstore_to_string(object)
-
if Hash === object
-
object.map { |k,v|
-
"#{escape_hstore(k)}=>#{escape_hstore(v)}"
-
}.join ','
-
else
-
object
-
end
-
end
-
-
1
def string_to_hstore(string)
-
if string.nil?
-
nil
-
elsif String === string
-
Hash[string.scan(HstorePair).map { |k,v|
-
v = v.upcase == 'NULL' ? nil : v.gsub(/^"(.*)"$/,'\1').gsub(/\\(.)/, '\1')
-
k = k.gsub(/^"(.*)"$/,'\1').gsub(/\\(.)/, '\1')
-
[k,v]
-
}]
-
else
-
string
-
end
-
end
-
-
1
def json_to_string(object)
-
6
if Hash === object
-
6
ActiveSupport::JSON.encode(object)
-
else
-
object
-
end
-
end
-
-
1
def array_to_string(value, column, adapter, should_be_quoted = false)
-
25
casted_values = value.map do |val|
-
46
if String === val
-
34
if val == "NULL"
-
4
"\"#{val}\""
-
else
-
30
quote_and_escape(adapter.type_cast(val, column, true))
-
end
-
else
-
12
adapter.type_cast(val, column, true)
-
end
-
end
-
25
"{#{casted_values.join(',')}}"
-
end
-
-
1
def string_to_json(string)
-
if String === string
-
ActiveSupport::JSON.decode(string)
-
else
-
string
-
end
-
end
-
-
1
def string_to_cidr(string)
-
10
if string.nil?
-
nil
-
10
elsif String === string
-
10
IPAddr.new(string)
-
else
-
string
-
end
-
end
-
-
1
def cidr_to_string(object)
-
4
if IPAddr === object
-
4
"#{object.to_s}/#{object.instance_variable_get(:@mask_addr).to_s(2).count('1')}"
-
else
-
object
-
end
-
end
-
-
1
def string_to_array(string, oid)
-
113
parse_pg_array(string).map{|val| oid.type_cast val}
-
end
-
-
1
private
-
-
1
HstorePair = begin
-
1
quoted_string = /"[^"\\]*(?:\\.[^"\\]*)*"/
-
1
unquoted_string = /(?:\\.|[^\s,])[^\s=,\\]*(?:\\.[^\s=,\\]*|=[^,>])*/
-
1
/(#{quoted_string}|#{unquoted_string})\s*=>\s*(#{quoted_string}|#{unquoted_string})/
-
end
-
-
1
def escape_hstore(value)
-
if value.nil?
-
'NULL'
-
else
-
if value == ""
-
'""'
-
else
-
'"%s"' % value.to_s.gsub(/(["\\])/, '\\\\\1')
-
end
-
end
-
end
-
-
1
def quote_and_escape(value)
-
30
case value
-
when "NULL"
-
value
-
else
-
30
"\"#{value.gsub(/"/,"\\\"")}\""
-
end
-
end
-
end
-
end
-
end
-
end
-
1
require 'active_support/deprecation'
-
-
1
module ActiveRecord
-
1
module ConnectionAdapters
-
1
class PostgreSQLAdapter < AbstractAdapter
-
1
module DatabaseStatements
-
1
def explain(arel, binds = [])
-
5
sql = "EXPLAIN #{to_sql(arel, binds)}"
-
5
ExplainPrettyPrinter.new.pp(exec_query(sql, 'EXPLAIN', binds))
-
end
-
-
1
class ExplainPrettyPrinter # :nodoc:
-
# Pretty prints the result of a EXPLAIN in a way that resembles the output of the
-
# PostgreSQL shell:
-
#
-
# QUERY PLAN
-
# ------------------------------------------------------------------------------
-
# Nested Loop Left Join (cost=0.00..37.24 rows=8 width=0)
-
# Join Filter: (posts.user_id = users.id)
-
# -> Index Scan using users_pkey on users (cost=0.00..8.27 rows=1 width=4)
-
# Index Cond: (id = 1)
-
# -> Seq Scan on posts (cost=0.00..28.88 rows=8 width=4)
-
# Filter: (posts.user_id = 1)
-
# (6 rows)
-
#
-
1
def pp(result)
-
5
header = result.columns.first
-
5
lines = result.rows.map(&:first)
-
-
# We add 2 because there's one char of padding at both sides, note
-
# the extra hyphens in the example above.
-
5
width = [header, *lines].map(&:length).max + 2
-
-
5
pp = []
-
-
5
pp << header.center(width).rstrip
-
5
pp << '-' * width
-
-
16
pp += lines.map {|line| " #{line}"}
-
-
5
nrows = result.rows.length
-
5
rows_label = nrows == 1 ? 'row' : 'rows'
-
5
pp << "(#{nrows} #{rows_label})"
-
-
5
pp.join("\n") + "\n"
-
end
-
end
-
-
# Executes a SELECT query and returns an array of rows. Each row is an
-
# array of field values.
-
1
def select_rows(sql, name = nil)
-
8
select_raw(sql, name).last
-
end
-
-
# Executes an INSERT query and returns the new record's ID
-
1
def insert_sql(sql, name = nil, pk = nil, id_value = nil, sequence_name = nil)
-
4
unless pk
-
# Extract the table from the insert sql. Yuck.
-
3
table_ref = extract_table_ref_from_insert_sql(sql)
-
3
pk = primary_key(table_ref) if table_ref
-
end
-
-
4
if pk && use_insert_returning?
-
3
select_value("#{sql} RETURNING #{quote_column_name(pk)}")
-
1
elsif pk
-
1
super
-
1
last_insert_id_value(sequence_name || default_sequence_name(table_ref, pk))
-
else
-
super
-
end
-
end
-
-
1
def create
-
super.insert
-
end
-
-
# create a 2D array representing the result set
-
1
def result_as_array(res) #:nodoc:
-
# check if we have any binary column and if they need escaping
-
9703
ftypes = Array.new(res.nfields) do |i|
-
30061
[i, res.ftype(i)]
-
end
-
-
9703
rows = res.values
-
9703
return rows unless ftypes.any? { |_, x|
-
30061
x == BYTEA_COLUMN_TYPE_OID || x == MONEY_COLUMN_TYPE_OID
-
}
-
-
typehash = ftypes.group_by { |_, type| type }
-
binaries = typehash[BYTEA_COLUMN_TYPE_OID] || []
-
monies = typehash[MONEY_COLUMN_TYPE_OID] || []
-
-
rows.each do |row|
-
# unescape string passed BYTEA field (OID == 17)
-
binaries.each do |index, _|
-
row[index] = unescape_bytea(row[index])
-
end
-
-
# If this is a money type column and there are any currency symbols,
-
# then strip them off. Indeed it would be prettier to do this in
-
# PostgreSQLColumn.string_to_decimal but would break form input
-
# fields that call value_before_type_cast.
-
monies.each do |index, _|
-
data = row[index]
-
# Because money output is formatted according to the locale, there are two
-
# cases to consider (note the decimal separators):
-
# (1) $12,345,678.12
-
# (2) $12.345.678,12
-
case data
-
when /^-?\D+[\d,]+\.\d{2}$/ # (1)
-
data.gsub!(/[^-\d.]/, '')
-
when /^-?\D+[\d.]+,\d{2}$/ # (2)
-
data.gsub!(/[^-\d,]/, '').sub!(/,/, '.')
-
end
-
end
-
end
-
end
-
-
# Queries the database and returns the results in an Array-like object
-
1
def query(sql, name = nil) #:nodoc:
-
9700
log(sql, name) do
-
9700
result_as_array @connection.async_exec(sql)
-
end
-
end
-
-
# Executes an SQL statement, returning a PGresult object on success
-
# or raising a PGError exception otherwise.
-
1
def execute(sql, name = nil)
-
33966
log(sql, name) do
-
33966
@connection.async_exec(sql)
-
end
-
end
-
-
1
def substitute_at(column, index)
-
12613
Arel::Nodes::BindParam.new "$#{index + 1}"
-
end
-
-
1
def exec_query(sql, name = 'SQL', binds = [])
-
22097
log(sql, name, binds) do
-
22097
result = binds.empty? ? exec_no_cache(sql, binds) :
-
exec_cache(sql, binds)
-
-
22080
types = {}
-
22080
result.fields.each_with_index do |fname, i|
-
115997
ftype = result.ftype i
-
115997
fmod = result.fmod i
-
115997
types[fname] = OID::TYPE_MAP.fetch(ftype, fmod) { |oid, mod|
-
warn "unknown OID: #{fname}(#{oid}) (#{sql})"
-
OID::Identity.new
-
}
-
end
-
-
22080
ret = ActiveRecord::Result.new(result.fields, result.values, types)
-
22080
result.clear
-
22080
return ret
-
end
-
end
-
-
1
def exec_delete(sql, name = 'SQL', binds = [])
-
2100
log(sql, name, binds) do
-
2100
result = binds.empty? ? exec_no_cache(sql, binds) :
-
exec_cache(sql, binds)
-
2098
affected = result.cmd_tuples
-
2098
result.clear
-
2098
affected
-
end
-
end
-
1
alias :exec_update :exec_delete
-
-
1
def sql_for_insert(sql, pk, id_value, sequence_name, binds)
-
2509
unless pk
-
# Extract the table from the insert sql. Yuck.
-
245
table_ref = extract_table_ref_from_insert_sql(sql)
-
245
pk = primary_key(table_ref) if table_ref
-
end
-
-
2509
if pk && use_insert_returning?
-
2266
sql = "#{sql} RETURNING #{quote_column_name(pk)}"
-
end
-
-
2509
[sql, binds]
-
end
-
-
1
def exec_insert(sql, name, binds, pk = nil, sequence_name = nil)
-
2512
val = exec_query(sql, name, binds)
-
2512
if !use_insert_returning? && pk
-
2
unless sequence_name
-
1
table_ref = extract_table_ref_from_insert_sql(sql)
-
1
sequence_name = default_sequence_name(table_ref, pk)
-
1
return val unless sequence_name
-
end
-
2
last_insert_id_result(sequence_name)
-
else
-
2510
val
-
end
-
end
-
-
# Executes an UPDATE query and returns the number of affected tuples.
-
1
def update_sql(sql, name = nil)
-
super.cmd_tuples
-
end
-
-
# Begins a transaction.
-
1
def begin_db_transaction
-
10188
execute "BEGIN"
-
end
-
-
1
def begin_isolated_db_transaction(isolation)
-
4
begin_db_transaction
-
4
execute "SET TRANSACTION ISOLATION LEVEL #{transaction_isolation_levels.fetch(isolation)}"
-
end
-
-
# Commits a transaction.
-
1
def commit_db_transaction
-
419
execute "COMMIT"
-
end
-
-
# Aborts a transaction.
-
1
def rollback_db_transaction
-
9766
execute "ROLLBACK"
-
end
-
-
1
def outside_transaction?
-
6
message = "#outside_transaction? is deprecated. This method was only really used " \
-
"internally, but you can use #transaction_open? instead."
-
6
ActiveSupport::Deprecation.warn message
-
6
@connection.transaction_status == PGconn::PQTRANS_IDLE
-
end
-
-
1
def create_savepoint
-
2827
execute("SAVEPOINT #{current_savepoint_name}")
-
end
-
-
1
def rollback_to_savepoint
-
215
execute("ROLLBACK TO SAVEPOINT #{current_savepoint_name}")
-
end
-
-
1
def release_savepoint
-
2612
execute("RELEASE SAVEPOINT #{current_savepoint_name}")
-
end
-
end
-
end
-
end
-
end
-
1
require 'active_record/connection_adapters/abstract_adapter'
-
-
1
module ActiveRecord
-
1
module ConnectionAdapters
-
1
class PostgreSQLAdapter < AbstractAdapter
-
1
module OID
-
1
class Type
-
1
def type; end
-
-
1
def type_cast_for_write(value)
-
value
-
end
-
end
-
-
1
class Identity < Type
-
1
def type_cast(value)
-
10234
value
-
end
-
end
-
-
1
class Bytea < Type
-
1
def type_cast(value)
-
9
PGconn.unescape_bytea value
-
end
-
end
-
-
1
class Money < Type
-
1
def type_cast(value)
-
6
return if value.nil?
-
-
# Because money output is formatted according to the locale, there are two
-
# cases to consider (note the decimal separators):
-
# (1) $12,345,678.12
-
# (2) $12.345.678,12
-
-
6
case value
-
when /^-?\D+[\d,]+\.\d{2}$/ # (1)
-
4
value.gsub!(/[^-\d.]/, '')
-
when /^-?\D+[\d.]+,\d{2}$/ # (2)
-
value.gsub!(/[^-\d,]/, '').sub!(/,/, '.')
-
end
-
-
6
ConnectionAdapters::Column.value_to_decimal value
-
end
-
end
-
-
1
class Vector < Type
-
1
attr_reader :delim, :subtype
-
-
# +delim+ corresponds to the `typdelim` column in the pg_types
-
# table. +subtype+ is derived from the `typelem` column in the
-
# pg_types table.
-
1
def initialize(delim, subtype)
-
663
@delim = delim
-
663
@subtype = subtype
-
end
-
-
# FIXME: this should probably split on +delim+ and use +subtype+
-
# to cast the values. Unfortunately, the current Rails behavior
-
# is to just return the string.
-
1
def type_cast(value)
-
18
value
-
end
-
end
-
-
1
class Array < Type
-
1
attr_reader :subtype
-
1
def initialize(subtype)
-
3513
@subtype = subtype
-
end
-
-
1
def type_cast(value)
-
75
if String === value
-
29
ConnectionAdapters::PostgreSQLColumn.string_to_array value, @subtype
-
else
-
46
value
-
end
-
end
-
end
-
-
1
class Integer < Type
-
1
def type_cast(value)
-
31216
return if value.nil?
-
-
30654
value.to_i rescue value ? 1 : 0
-
end
-
end
-
-
1
class Boolean < Type
-
1
def type_cast(value)
-
1560
return if value.nil?
-
-
1549
ConnectionAdapters::Column.value_to_boolean value
-
end
-
end
-
-
1
class Timestamp < Type
-
24
def type; :timestamp; end
-
-
1
def type_cast(value)
-
5963
return if value.nil?
-
-
# FIXME: probably we can improve this since we know it is PG
-
# specific
-
5890
ConnectionAdapters::PostgreSQLColumn.string_to_time value
-
end
-
end
-
-
1
class Date < Type
-
7
def type; :datetime; end
-
-
1
def type_cast(value)
-
203
return if value.nil?
-
-
# FIXME: probably we can improve this since we know it is PG
-
# specific
-
150
ConnectionAdapters::Column.value_to_date value
-
end
-
end
-
-
1
class Time < Type
-
1
def type_cast(value)
-
143
return if value.nil?
-
-
# FIXME: probably we can improve this since we know it is PG
-
# specific
-
106
ConnectionAdapters::Column.string_to_dummy_time value
-
end
-
end
-
-
1
class Float < Type
-
1
def type_cast(value)
-
14
return if value.nil?
-
-
14
value.to_f
-
end
-
end
-
-
1
class Decimal < Type
-
1
def type_cast(value)
-
94
return if value.nil?
-
-
94
ConnectionAdapters::Column.value_to_decimal value
-
end
-
end
-
-
1
class Hstore < Type
-
1
def type_cast(value)
-
return if value.nil?
-
-
ConnectionAdapters::PostgreSQLColumn.string_to_hstore value
-
end
-
end
-
-
1
class Cidr < Type
-
1
def type_cast(value)
-
10
return if value.nil?
-
-
10
ConnectionAdapters::PostgreSQLColumn.string_to_cidr value
-
end
-
end
-
-
1
class Json < Type
-
1
def type_cast(value)
-
return if value.nil?
-
-
ConnectionAdapters::PostgreSQLColumn.string_to_json value
-
end
-
end
-
-
1
class TypeMap
-
1
def initialize
-
1
@mapping = {}
-
end
-
-
1
def []=(oid, type)
-
7305
@mapping[oid] = type
-
end
-
-
1
def [](oid)
-
4176
@mapping[oid]
-
end
-
-
1
def key?(oid)
-
19945
@mapping.key? oid
-
end
-
-
1
def fetch(ftype, fmod)
-
# The type for the numeric depends on the width of the field,
-
# so we'll do something special here.
-
#
-
# When dealing with decimal columns:
-
#
-
# places after decimal = fmod - 4 & 0xffff
-
# places before decimal = (fmod - 4) >> 16 & 0xffff
-
169527
if ftype == 1700 && (fmod - 4 & 0xffff).zero?
-
91
ftype = 23
-
end
-
-
169527
@mapping.fetch(ftype) { |oid| yield oid, fmod }
-
end
-
end
-
-
1
TYPE_MAP = TypeMap.new # :nodoc:
-
-
# When the PG adapter connects, the pg_type table is queried. The
-
# key of this hash maps to the `typname` column from the table.
-
# TYPE_MAP is then dynamically built with oids as the key and type
-
# objects as values.
-
1
NAMES = Hash.new { |h,k| # :nodoc:
-
h[k] = OID::Identity.new
-
}
-
-
# Register an OID type named +name+ with a typcasting object in
-
# +type+. +name+ should correspond to the `typname` column in
-
# the `pg_type` table.
-
1
def self.register_type(name, type)
-
17
NAMES[name] = type
-
end
-
-
# Alias the +old+ type to the +new+ type.
-
1
def self.alias_type(new, old)
-
15
NAMES[new] = NAMES[old]
-
end
-
-
# Is +name+ a registered type?
-
1
def self.registered_type?(name)
-
52462
NAMES.key? name
-
end
-
-
1
register_type 'int2', OID::Integer.new
-
1
alias_type 'int4', 'int2'
-
1
alias_type 'int8', 'int2'
-
1
alias_type 'oid', 'int2'
-
-
1
register_type 'numeric', OID::Decimal.new
-
1
register_type 'text', OID::Identity.new
-
1
alias_type 'varchar', 'text'
-
1
alias_type 'char', 'text'
-
1
alias_type 'bpchar', 'text'
-
1
alias_type 'xml', 'text'
-
-
# FIXME: why are we keeping these types as strings?
-
1
alias_type 'tsvector', 'text'
-
1
alias_type 'interval', 'text'
-
1
alias_type 'bit', 'text'
-
1
alias_type 'varbit', 'text'
-
1
alias_type 'macaddr', 'text'
-
1
alias_type 'uuid', 'text'
-
-
# FIXME: I don't think this is correct. We should probably be returning a parsed date,
-
# but the tests pass with a string returned.
-
1
register_type 'timestamptz', OID::Identity.new
-
-
1
register_type 'money', OID::Money.new
-
1
register_type 'bytea', OID::Bytea.new
-
1
register_type 'bool', OID::Boolean.new
-
-
1
register_type 'float4', OID::Float.new
-
1
alias_type 'float8', 'float4'
-
-
1
register_type 'timestamp', OID::Timestamp.new
-
1
register_type 'date', OID::Date.new
-
1
register_type 'time', OID::Time.new
-
-
1
register_type 'path', OID::Identity.new
-
1
register_type 'polygon', OID::Identity.new
-
1
register_type 'circle', OID::Identity.new
-
1
register_type 'hstore', OID::Hstore.new
-
1
register_type 'json', OID::Json.new
-
-
1
register_type 'cidr', OID::Cidr.new
-
1
alias_type 'inet', 'cidr'
-
end
-
end
-
end
-
end
-
1
module ActiveRecord
-
1
module ConnectionAdapters
-
1
class PostgreSQLAdapter < AbstractAdapter
-
1
module Quoting
-
# Escapes binary strings for bytea input to the database.
-
1
def escape_bytea(value)
-
23
PGconn.escape_bytea(value) if value
-
end
-
-
# Unescapes bytea output from a database to the binary string it represents.
-
# NOTE: This is NOT an inverse of escape_bytea! This is only to be used
-
# on escaped binary output from database drive.
-
1
def unescape_bytea(value)
-
PGconn.unescape_bytea(value) if value
-
end
-
-
# Quotes PostgreSQL-specific data types for SQL input.
-
1
def quote(value, column = nil) #:nodoc:
-
27936
return super unless column
-
-
27553
case value
-
when Array
-
32
if column.array
-
9
"'#{PostgreSQLColumn.array_to_string(value, column, self)}'"
-
else
-
23
super
-
end
-
when Hash
-
8
case column.sql_type
-
when 'hstore' then super(PostgreSQLColumn.hstore_to_string(value), column)
-
6
when 'json' then super(PostgreSQLColumn.json_to_string(value), column)
-
2
else super
-
end
-
when IPAddr
-
2
case column.sql_type
-
2
when 'inet', 'cidr' then super(PostgreSQLColumn.cidr_to_string(value), column)
-
else super
-
end
-
when Float
-
5
if value.infinite? && column.type == :datetime
-
"'#{value.to_s.downcase}'"
-
5
elsif value.infinite? || value.nan?
-
2
"'#{value.to_s}'"
-
else
-
3
super
-
end
-
when Numeric
-
9522
return super unless column.sql_type == 'money'
-
# Not truly string input, so doesn't require (or allow) escape string syntax.
-
1
"'#{value}'"
-
when String
-
16263
case column.sql_type
-
23
when 'bytea' then "'#{escape_bytea(value)}'"
-
when 'xml' then "xml '#{quote_string(value)}'"
-
when /^bit/
-
2
case value
-
1
when /^[01]*$/ then "B'#{value}'" # Bit-string notation
-
1
when /^[0-9A-F]*$/i then "X'#{value}'" # Hexadecimal notation
-
end
-
else
-
16238
super
-
end
-
else
-
1721
super
-
end
-
end
-
-
1
def type_cast(value, column, array_member = false)
-
11725
return super(value, column) unless column
-
-
11715
case value
-
when NilClass
-
113
if column.array && array_member
-
4
'NULL'
-
109
elsif column.array
-
value
-
else
-
109
super(value, column)
-
end
-
when Array
-
16
return super(value, column) unless column.array
-
16
PostgreSQLColumn.array_to_string(value, column, self)
-
when String
-
2629
return super(value, column) unless 'bytea' == column.sql_type
-
4
{ :value => value, :format => 1 }
-
when Hash
-
case column.sql_type
-
when 'hstore' then PostgreSQLColumn.hstore_to_string(value)
-
when 'json' then PostgreSQLColumn.json_to_string(value)
-
else super(value, column)
-
end
-
when IPAddr
-
2
return super(value, column) unless ['inet','cidr'].include? column.sql_type
-
2
PostgreSQLColumn.cidr_to_string(value)
-
else
-
8955
super(value, column)
-
end
-
end
-
-
# Quotes strings for use in SQL input.
-
1
def quote_string(s) #:nodoc:
-
15006
@connection.escape(s)
-
end
-
-
# Checks the following cases:
-
#
-
# - table_name
-
# - "table.name"
-
# - schema_name.table_name
-
# - schema_name."table.name"
-
# - "schema.name".table_name
-
# - "schema.name"."table.name"
-
1
def quote_table_name(name)
-
97633
schema, name_part = extract_pg_identifier_from_name(name.to_s)
-
-
97633
unless name_part
-
97602
quote_column_name(schema)
-
else
-
31
table_name, name_part = extract_pg_identifier_from_name(name_part)
-
31
"#{quote_column_name(schema)}.#{quote_column_name(table_name)}"
-
end
-
end
-
-
# Quotes column names for use in SQL queries.
-
1
def quote_column_name(name) #:nodoc:
-
124471
PGconn.quote_ident(name.to_s)
-
end
-
-
# Quote date/time values for use in SQL input. Includes microseconds
-
# if the value is a Time responding to usec.
-
1
def quoted_date(value) #:nodoc:
-
3051
if value.acts_like?(:time) && value.respond_to?(:usec)
-
2911
"#{super}.#{sprintf("%06d", value.usec)}"
-
else
-
140
super
-
end
-
end
-
end
-
end
-
end
-
end
-
1
module ActiveRecord
-
1
module ConnectionAdapters
-
1
class PostgreSQLAdapter < AbstractAdapter
-
1
module ReferentialIntegrity
-
1
def supports_disable_referential_integrity? #:nodoc:
-
504
true
-
end
-
-
1
def disable_referential_integrity #:nodoc:
-
252
if supports_disable_referential_integrity? then
-
34542
execute(tables.collect { |name| "ALTER TABLE #{quote_table_name(name)} DISABLE TRIGGER ALL" }.join(";"))
-
end
-
252
yield
-
ensure
-
252
if supports_disable_referential_integrity? then
-
34542
execute(tables.collect { |name| "ALTER TABLE #{quote_table_name(name)} ENABLE TRIGGER ALL" }.join(";"))
-
end
-
end
-
end
-
end
-
end
-
end
-
1
module ActiveRecord
-
1
module ConnectionAdapters
-
1
class PostgreSQLAdapter < AbstractAdapter
-
1
module SchemaStatements
-
# Drops the database specified on the +name+ attribute
-
# and creates it again using the provided +options+.
-
1
def recreate_database(name, options = {}) #:nodoc:
-
drop_database(name)
-
create_database(name, options)
-
end
-
-
# Create a new PostgreSQL database. Options include <tt>:owner</tt>, <tt>:template</tt>,
-
# <tt>:encoding</tt>, <tt>:collation</tt>, <tt>:ctype</tt>,
-
# <tt>:tablespace</tt>, and <tt>:connection_limit</tt> (note that MySQL uses
-
# <tt>:charset</tt> while PostgreSQL uses <tt>:encoding</tt>).
-
#
-
# Example:
-
# create_database config[:database], config
-
# create_database 'foo_development', encoding: 'unicode'
-
1
def create_database(name, options = {})
-
3
options = options.reverse_merge(:encoding => "utf8")
-
-
3
option_string = options.symbolize_keys.sum do |key, value|
-
5
case key
-
when :owner
-
" OWNER = \"#{value}\""
-
when :template
-
" TEMPLATE = \"#{value}\""
-
when :encoding
-
3
" ENCODING = '#{value}'"
-
when :collation
-
1
" LC_COLLATE = '#{value}'"
-
when :ctype
-
1
" LC_CTYPE = '#{value}'"
-
when :tablespace
-
" TABLESPACE = \"#{value}\""
-
when :connection_limit
-
" CONNECTION LIMIT = #{value}"
-
else
-
""
-
end
-
end
-
-
3
execute "CREATE DATABASE #{quote_table_name(name)}#{option_string}"
-
end
-
-
# Drops a PostgreSQL database.
-
#
-
# Example:
-
# drop_database 'matt_development'
-
1
def drop_database(name) #:nodoc:
-
execute "DROP DATABASE IF EXISTS #{quote_table_name(name)}"
-
end
-
-
# Returns the list of all tables in the schema search path or a specified schema.
-
1
def tables(name = nil)
-
78129
query(<<-SQL, 'SCHEMA').map { |row| row[0] }
-
SELECT tablename
-
FROM pg_tables
-
WHERE schemaname = ANY (current_schemas(false))
-
SQL
-
end
-
-
# Returns true if table exists.
-
# If the schema is not specified as part of +name+ then it will only find tables within
-
# the current schema search path (regardless of permissions to access tables in other schemas)
-
1
def table_exists?(name)
-
866
schema, table = Utils.extract_schema_and_table(name.to_s)
-
866
return false unless table
-
-
864
binds = [[nil, table]]
-
864
binds << [nil, schema] if schema
-
-
exec_query(<<-SQL, 'SCHEMA').rows.first[0].to_i > 0
-
SELECT COUNT(*)
-
FROM pg_class c
-
LEFT JOIN pg_namespace n ON n.oid = c.relnamespace
-
WHERE c.relkind in ('v','r')
-
AND c.relname = '#{table.gsub(/(^"|"$)/,'')}'
-
AND n.nspname = #{schema ? "'#{schema}'" : 'ANY (current_schemas(false))'}
-
864
SQL
-
end
-
-
# Returns true if schema exists.
-
1
def schema_exists?(name)
-
exec_query(<<-SQL, 'SCHEMA').rows.first[0].to_i > 0
-
SELECT COUNT(*)
-
FROM pg_namespace
-
WHERE nspname = '#{name}'
-
4
SQL
-
end
-
-
# Returns an array of indexes for the given table.
-
1
def indexes(table_name, name = nil)
-
3791
result = query(<<-SQL, 'SCHEMA')
-
SELECT distinct i.relname, d.indisunique, d.indkey, pg_get_indexdef(d.indexrelid), t.oid
-
FROM pg_class t
-
INNER JOIN pg_index d ON t.oid = d.indrelid
-
INNER JOIN pg_class i ON d.indexrelid = i.oid
-
WHERE i.relkind = 'i'
-
AND d.indisprimary = 'f'
-
AND t.relname = '#{table_name}'
-
AND i.relnamespace IN (SELECT oid FROM pg_namespace WHERE nspname = ANY (current_schemas(false)) )
-
ORDER BY i.relname
-
SQL
-
-
3791
result.map do |row|
-
175
index_name = row[0]
-
175
unique = row[1] == 't'
-
175
indkey = row[2].split(" ")
-
175
inddef = row[3]
-
175
oid = row[4]
-
-
175
columns = Hash[query(<<-SQL, "SCHEMA")]
-
SELECT a.attnum, a.attname
-
FROM pg_attribute a
-
WHERE a.attrelid = #{oid}
-
AND a.attnum IN (#{indkey.join(",")})
-
SQL
-
-
175
column_names = columns.values_at(*indkey).compact
-
-
# add info on sort order for columns (only desc order is explicitly specified, asc is the default)
-
175
desc_order_columns = inddef.scan(/(\w+) DESC/).flatten
-
178
orders = desc_order_columns.any? ? Hash[desc_order_columns.map {|order_column| [order_column, :desc]}] : {}
-
175
where = inddef.scan(/WHERE (.+)$/).flatten[0]
-
-
175
column_names.empty? ? nil : IndexDefinition.new(table_name, index_name, unique, column_names, [], orders, where)
-
end.compact
-
end
-
-
# Returns the list of all column definitions for a table.
-
1
def columns(table_name)
-
# Limit, precision, and scale are all handled by the superclass.
-
9125
column_definitions(table_name).map do |column_name, type, default, notnull, oid, fmod|
-
53530
oid = OID::TYPE_MAP.fetch(oid.to_i, fmod.to_i) {
-
OID::Identity.new
-
}
-
53530
PostgreSQLColumn.new(column_name, default, oid, type, notnull == 'f')
-
end
-
end
-
-
# Returns the current database name.
-
1
def current_database
-
6
query('select current_database()', 'SCHEMA')[0][0]
-
end
-
-
# Returns the current schema name.
-
1
def current_schema
-
4
query('SELECT current_schema', 'SCHEMA')[0][0]
-
end
-
-
# Returns the current database encoding format.
-
1
def encoding
-
2
query(<<-end_sql, 'SCHEMA')[0][0]
-
SELECT pg_encoding_to_char(pg_database.encoding) FROM pg_database
-
WHERE pg_database.datname LIKE '#{current_database}'
-
end_sql
-
end
-
-
# Returns the current database collation.
-
1
def collation
-
1
query(<<-end_sql, 'SCHEMA')[0][0]
-
SELECT pg_database.datcollate FROM pg_database WHERE pg_database.datname LIKE '#{current_database}'
-
end_sql
-
end
-
-
# Returns the current database ctype.
-
1
def ctype
-
1
query(<<-end_sql, 'SCHEMA')[0][0]
-
SELECT pg_database.datctype FROM pg_database WHERE pg_database.datname LIKE '#{current_database}'
-
end_sql
-
end
-
-
# Returns an array of schema names.
-
1
def schema_names
-
4
query(<<-SQL, 'SCHEMA').flatten
-
SELECT nspname
-
FROM pg_namespace
-
WHERE nspname !~ '^pg_.*'
-
AND nspname NOT IN ('information_schema')
-
ORDER by nspname;
-
SQL
-
end
-
-
# Creates a schema for the given schema name.
-
1
def create_schema schema_name
-
4
execute "CREATE SCHEMA #{schema_name}"
-
end
-
-
# Drops the schema for the given schema name.
-
1
def drop_schema schema_name
-
4
execute "DROP SCHEMA #{schema_name} CASCADE"
-
end
-
-
# Sets the schema search path to a string of comma-separated schema names.
-
# Names beginning with $ have to be quoted (e.g. $user => '$user').
-
# See: http://www.postgresql.org/docs/current/static/ddl-schemas.html
-
#
-
# This should be not be called manually but set in database.yml.
-
1
def schema_search_path=(schema_csv)
-
148
if schema_csv
-
46
execute("SET search_path TO #{schema_csv}", 'SCHEMA')
-
45
@schema_search_path = schema_csv
-
end
-
end
-
-
# Returns the active schema search path.
-
1
def schema_search_path
-
7839
@schema_search_path ||= query('SHOW search_path', 'SCHEMA')[0][0]
-
end
-
-
# Returns the current client message level.
-
1
def client_min_messages
-
102
query('SHOW client_min_messages', 'SCHEMA')[0][0]
-
end
-
-
# Set the client message level.
-
1
def client_min_messages=(level)
-
303
execute("SET client_min_messages TO '#{level}'", 'SCHEMA')
-
end
-
-
# Returns the sequence name for a table's primary key or some other specified key.
-
1
def default_sequence_name(table_name, pk = nil) #:nodoc:
-
63
result = serial_sequence(table_name, pk || 'id')
-
57
return nil unless result
-
57
result.split('.').last
-
rescue ActiveRecord::StatementInvalid
-
6
"#{table_name}_#{pk || 'id'}_seq"
-
end
-
-
1
def serial_sequence(table, column)
-
65
result = exec_query(<<-eosql, 'SCHEMA')
-
SELECT pg_get_serial_sequence('#{table}', '#{column}')
-
eosql
-
58
result.rows.first.first
-
end
-
-
# Resets the sequence of a table's primary key to the maximum value.
-
1
def reset_pk_sequence!(table, pk = nil, sequence = nil) #:nodoc:
-
837
unless pk and sequence
-
835
default_pk, default_sequence = pk_and_sequence_for(table)
-
-
835
pk ||= default_pk
-
835
sequence ||= default_sequence
-
end
-
-
837
if @logger && pk && !sequence
-
@logger.warn "#{table} has primary key #{pk} with no default sequence"
-
end
-
-
837
if pk && sequence
-
799
quoted_sequence = quote_table_name(sequence)
-
-
799
select_value <<-end_sql, 'SCHEMA'
-
SELECT setval('#{quoted_sequence}', (SELECT COALESCE(MAX(#{quote_column_name pk})+(SELECT increment_by FROM #{quoted_sequence}), (SELECT min_value FROM #{quoted_sequence})) FROM #{quote_table_name(table)}), false)
-
end_sql
-
end
-
end
-
-
# Returns a table's primary key and belonging sequence.
-
1
def pk_and_sequence_for(table) #:nodoc:
-
# First try looking for a sequence with a dependency on the
-
# given table's primary key.
-
4507
result = query(<<-end_sql, 'SCHEMA')[0]
-
SELECT attr.attname, seq.relname
-
FROM pg_class seq,
-
pg_attribute attr,
-
pg_depend dep,
-
pg_namespace name,
-
pg_constraint cons
-
WHERE seq.oid = dep.objid
-
AND seq.relkind = 'S'
-
AND attr.attrelid = dep.refobjid
-
AND attr.attnum = dep.refobjsubid
-
AND attr.attrelid = cons.conrelid
-
AND attr.attnum = cons.conkey[1]
-
AND cons.contype = 'p'
-
AND dep.refobjid = '#{quote_table_name(table)}'::regclass
-
end_sql
-
-
4502
if result.nil? or result.empty?
-
512
result = query(<<-end_sql, 'SCHEMA')[0]
-
SELECT attr.attname,
-
CASE
-
WHEN split_part(pg_get_expr(def.adbin, def.adrelid), '''', 2) ~ '.' THEN
-
substr(split_part(pg_get_expr(def.adbin, def.adrelid), '''', 2),
-
strpos(split_part(pg_get_expr(def.adbin, def.adrelid), '''', 2), '.')+1)
-
ELSE split_part(pg_get_expr(def.adbin, def.adrelid), '''', 2)
-
END
-
FROM pg_class t
-
JOIN pg_attribute attr ON (t.oid = attrelid)
-
JOIN pg_attrdef def ON (adrelid = attrelid AND adnum = attnum)
-
JOIN pg_constraint cons ON (conrelid = adrelid AND adnum = conkey[1])
-
WHERE t.oid = '#{quote_table_name(table)}'::regclass
-
AND cons.contype = 'p'
-
AND pg_get_expr(def.adbin, def.adrelid) ~* 'nextval'
-
end_sql
-
end
-
-
4502
[result.first, result.last]
-
rescue
-
516
nil
-
end
-
-
# Returns just a table's primary key
-
1
def primary_key(table)
-
411
row = exec_query(<<-end_sql, 'SCHEMA').rows.first
-
SELECT DISTINCT(attr.attname)
-
FROM pg_attribute attr
-
INNER JOIN pg_depend dep ON attr.attrelid = dep.refobjid AND attr.attnum = dep.refobjsubid
-
INNER JOIN pg_constraint cons ON attr.attrelid = cons.conrelid AND attr.attnum = cons.conkey[1]
-
WHERE cons.contype = 'p'
-
AND dep.refobjid = '#{quote_table_name(table)}'::regclass
-
end_sql
-
-
409
row && row.first
-
end
-
-
# Renames a table.
-
# Also renames a table's primary key sequence if the sequence name matches the
-
# Active Record default.
-
#
-
# Example:
-
# rename_table('octopuses', 'octopi')
-
1
def rename_table(name, new_name)
-
7
clear_cache!
-
7
execute "ALTER TABLE #{quote_table_name(name)} RENAME TO #{quote_table_name(new_name)}"
-
7
pk, seq = pk_and_sequence_for(new_name)
-
7
if seq == "#{name}_#{pk}_seq"
-
7
new_seq = "#{new_name}_#{pk}_seq"
-
7
execute "ALTER TABLE #{quote_table_name(seq)} RENAME TO #{quote_table_name(new_seq)}"
-
end
-
end
-
-
# Adds a new column to the named table.
-
# See TableDefinition#column for details of the options you can use.
-
1
def add_column(table_name, column_name, type, options = {})
-
105
clear_cache!
-
105
add_column_sql = "ALTER TABLE #{quote_table_name(table_name)} ADD COLUMN #{quote_column_name(column_name)} #{type_to_sql(type, options[:limit], options[:precision], options[:scale])}"
-
104
add_column_options!(add_column_sql, options)
-
-
104
execute add_column_sql
-
end
-
-
# Changes the column of a table.
-
1
def change_column(table_name, column_name, type, options = {})
-
15
clear_cache!
-
15
quoted_table_name = quote_table_name(table_name)
-
-
15
execute "ALTER TABLE #{quoted_table_name} ALTER COLUMN #{quote_column_name(column_name)} TYPE #{type_to_sql(type, options[:limit], options[:precision], options[:scale])}"
-
-
15
change_column_default(table_name, column_name, options[:default]) if options_include_default?(options)
-
15
change_column_null(table_name, column_name, options[:null], options[:default]) if options.key?(:null)
-
end
-
-
# Changes the default value of a table column.
-
1
def change_column_default(table_name, column_name, default)
-
10
clear_cache!
-
10
execute "ALTER TABLE #{quote_table_name(table_name)} ALTER COLUMN #{quote_column_name(column_name)} SET DEFAULT #{quote(default)}"
-
end
-
-
1
def change_column_null(table_name, column_name, null, default = nil)
-
8
clear_cache!
-
8
unless null || default.nil?
-
3
execute("UPDATE #{quote_table_name(table_name)} SET #{quote_column_name(column_name)}=#{quote(default)} WHERE #{quote_column_name(column_name)} IS NULL")
-
end
-
8
execute("ALTER TABLE #{quote_table_name(table_name)} ALTER #{quote_column_name(column_name)} #{null ? 'DROP' : 'SET'} NOT NULL")
-
end
-
-
# Renames a column in a table.
-
1
def rename_column(table_name, column_name, new_column_name)
-
8
clear_cache!
-
8
execute "ALTER TABLE #{quote_table_name(table_name)} RENAME COLUMN #{quote_column_name(column_name)} TO #{quote_column_name(new_column_name)}"
-
end
-
-
1
def remove_index!(table_name, index_name) #:nodoc:
-
23
execute "DROP INDEX #{quote_table_name(index_name)}"
-
end
-
-
1
def rename_index(table_name, old_name, new_name)
-
1
execute "ALTER INDEX #{quote_column_name(old_name)} RENAME TO #{quote_table_name(new_name)}"
-
end
-
-
1
def index_name_length
-
75
63
-
end
-
-
# Maps logical Rails types to PostgreSQL-specific data types.
-
1
def type_to_sql(type, limit = nil, precision = nil, scale = nil)
-
1313
case type.to_s
-
when 'binary'
-
# PostgreSQL doesn't support limits on binary (bytea) columns.
-
# The hard limit is 1Gb, because of a 32-bit size field, and TOAST.
-
3
case limit
-
3
when nil, 0..0x3fffffff; super(type)
-
else raise(ActiveRecordError, "No binary type has byte size #{limit}.")
-
end
-
when 'integer'
-
323
return 'integer' unless limit
-
-
13
case limit
-
3
when 1, 2; 'smallint'
-
3
when 3, 4; 'integer'
-
5
when 5..8; 'bigint'
-
2
else raise(ActiveRecordError, "No integer type has byte size #{limit}. Use a numeric with precision 0 instead.")
-
end
-
when 'datetime'
-
152
return super unless precision
-
-
9
case precision
-
8
when 0..6; "timestamp(#{precision})"
-
1
else raise(ActiveRecordError, "No timestamp type has precision of #{precision}. The allowed range of precision is from 0 to 6")
-
end
-
else
-
835
super
-
end
-
end
-
-
# Returns a SELECT DISTINCT clause for a given set of columns and a given ORDER BY clause.
-
#
-
# PostgreSQL requires the ORDER BY columns in the select list for distinct queries, and
-
# requires that the ORDER BY include the distinct column.
-
#
-
# distinct("posts.id", "posts.created_at desc")
-
1
def distinct(columns, orders) #:nodoc:
-
39
return "DISTINCT #{columns}" if orders.empty?
-
-
# Construct a clean list of column names from the ORDER BY clause, removing
-
# any ASC/DESC modifiers
-
22
order_columns = orders.collect do |s|
-
29
s = s.to_sql unless s.is_a?(String)
-
29
s.gsub(/\s+(ASC|DESC)\s*(NULLS\s+(FIRST|LAST)\s*)?/i, '')
-
end
-
51
order_columns.delete_if { |c| c.blank? }
-
51
order_columns = order_columns.zip((0...order_columns.size).to_a).map { |s,i| "#{s} AS alias_#{i}" }
-
-
22
"DISTINCT #{columns}, #{order_columns * ', '}"
-
end
-
end
-
end
-
end
-
end
-
1
require 'active_record/connection_adapters/abstract_adapter'
-
1
require 'active_record/connection_adapters/statement_pool'
-
1
require 'active_record/connection_adapters/postgresql/oid'
-
1
require 'active_record/connection_adapters/postgresql/cast'
-
1
require 'active_record/connection_adapters/postgresql/array_parser'
-
1
require 'active_record/connection_adapters/postgresql/quoting'
-
1
require 'active_record/connection_adapters/postgresql/schema_statements'
-
1
require 'active_record/connection_adapters/postgresql/database_statements'
-
1
require 'active_record/connection_adapters/postgresql/referential_integrity'
-
1
require 'arel/visitors/bind_visitor'
-
-
# Make sure we're using pg high enough for PGResult#values
-
1
gem 'pg', '~> 0.11'
-
1
require 'pg'
-
-
1
require 'ipaddr'
-
-
1
module ActiveRecord
-
1
module ConnectionHandling
-
# Establishes a connection to the database that's used by all Active Record objects
-
1
def postgresql_connection(config) # :nodoc:
-
95
conn_params = config.symbolize_keys
-
-
# Forward any unused config params to PGconn.connect.
-
95
[:statement_limit, :encoding, :min_messages, :schema_search_path,
-
:schema_order, :adapter, :pool, :checkout_timeout, :template,
-
:reaping_frequency, :insert_returning].each do |key|
-
1045
conn_params.delete key
-
end
-
192
conn_params.delete_if { |k,v| v.nil? }
-
-
# Map ActiveRecords param names to PGs.
-
95
conn_params[:user] = conn_params.delete(:username) if conn_params[:username]
-
95
conn_params[:dbname] = conn_params.delete(:database) if conn_params[:database]
-
-
# The postgres drivers don't allow the creation of an unconnected PGconn object,
-
# so just pass a nil connection object for the time being.
-
95
ConnectionAdapters::PostgreSQLAdapter.new(nil, logger, conn_params, config)
-
end
-
end
-
-
1
module ConnectionAdapters
-
# PostgreSQL-specific extensions to column definitions in a table.
-
1
class PostgreSQLColumn < Column #:nodoc:
-
1
attr_accessor :array
-
# Instantiates a new PostgreSQL column definition in a table.
-
1
def initialize(name, default, oid_type, sql_type = nil, null = true)
-
53532
@oid_type = oid_type
-
53532
if sql_type =~ /\[\]$/
-
53
@array = true
-
53
super(name, self.class.extract_value_from_default(default), sql_type[0..sql_type.length - 3], null)
-
else
-
53479
@array = false
-
53479
super(name, self.class.extract_value_from_default(default), sql_type, null)
-
end
-
end
-
-
# :stopdoc:
-
1
class << self
-
1
include ConnectionAdapters::PostgreSQLColumn::Cast
-
1
include ConnectionAdapters::PostgreSQLColumn::ArrayParser
-
1
attr_accessor :money_precision
-
end
-
# :startdoc:
-
-
# Extracts the value from a PostgreSQL column default definition.
-
1
def self.extract_value_from_default(default)
-
# This is a performance optimization for Ruby 1.9.2 in development.
-
# If the value is nil, we return nil straight away without checking
-
# the regular expressions. If we check each regular expression,
-
# Regexp#=== will call NilClass#to_str, which will trigger
-
# method_missing (defined by whiny nil in ActiveSupport) which
-
# makes this method very very slow.
-
53532
return default unless default
-
-
19189
case default
-
# Numeric types
-
when /\A\(?(-?\d+(\.\d*)?\)?)\z/
-
9440
$1
-
# Character types
-
when /\A\(?'(.*)'::.*\b(?:character varying|bpchar|text)\z/m
-
379
$1
-
# Binary data types
-
when /\A'(.*)'::bytea\z/m
-
$1
-
# Date/time types
-
when /\A'(.+)'::(?:time(?:stamp)? with(?:out)? time zone|date)\z/
-
52
$1
-
when /\A'(.*)'::interval\z/
-
$1
-
# Boolean type
-
when 'true'
-
601
true
-
when 'false'
-
140
false
-
# Geometric types
-
when /\A'(.*)'::(?:point|line|lseg|box|"?path"?|polygon|circle)\z/
-
$1
-
# Network address types
-
when /\A'(.*)'::(?:cidr|inet|macaddr)\z/
-
$1
-
# Bit string types
-
when /\AB'(.*)'::"?bit(?: varying)?"?\z/
-
$1
-
# XML type
-
when /\A'(.*)'::xml\z/m
-
$1
-
# Arrays
-
when /\A'(.*)'::"?\D+"?\[\]\z/
-
$1
-
# Hstore
-
when /\A'(.*)'::hstore\z/
-
$1
-
# JSON
-
when /\A'(.*)'::json\z/
-
$1
-
# Object identifier types
-
when /\A-?\d+\z/
-
$1
-
else
-
# Anything else is blank, some user type, or some function
-
# and we can't know the value of that, so return nil.
-
nil
-
end
-
end
-
-
1
def type_cast(value)
-
93543
return if value.nil?
-
33846
return super if encoded?
-
-
33846
@oid_type.type_cast value
-
end
-
-
1
private
-
-
1
def extract_limit(sql_type)
-
53532
case sql_type
-
106
when /^bigint/i; 8
-
54
when /^smallint/i; 2
-
when /^timestamp/i; nil
-
47433
else super
-
end
-
end
-
-
# Extracts the scale from PostgreSQL-specific data types.
-
1
def extract_scale(sql_type)
-
# Money type has a fixed scale of 2.
-
53746
sql_type =~ /^money/ ? 2 : super
-
end
-
-
# Extracts the precision from PostgreSQL-specific data types.
-
1
def extract_precision(sql_type)
-
53532
if sql_type == 'money'
-
26
self.class.money_precision
-
53506
elsif sql_type =~ /timestamp/i
-
5939
$1.to_i if sql_type =~ /\((\d+)\)/
-
else
-
47567
super
-
end
-
end
-
-
# Maps PostgreSQL-specific data types to logical Rails types.
-
1
def simplified_type(field_type)
-
53532
case field_type
-
# Numeric and monetary types
-
when /^(?:real|double precision)$/
-
81
:float
-
# Monetary types
-
when 'money'
-
26
:decimal
-
when 'hstore'
-
:hstore
-
# Network address types
-
when 'inet'
-
26
:inet
-
when 'cidr'
-
26
:cidr
-
when 'macaddr'
-
26
:macaddr
-
# Character types
-
when /^(?:character varying|bpchar)(?:\(\d+\))?$/
-
14451
:string
-
# Binary data types
-
when 'bytea'
-
145
:binary
-
# Date/time types
-
when /^timestamp with(?:out)? time zone$/
-
5927
:datetime
-
when /^interval(?:|\(\d+\))$/
-
52
:string
-
# Geometric types
-
when /^(?:point|line|lseg|box|"?path"?|polygon|circle)$/
-
156
:string
-
# Bit strings
-
when /^bit(?: varying)?(?:\(\d+\))?$/
-
52
:string
-
# XML type
-
when 'xml'
-
25
:xml
-
# tsvector type
-
when 'tsvector'
-
26
:tsvector
-
# Arrays
-
when /^\D+\[\]$/
-
:string
-
# Object identifier types
-
when 'oid'
-
26
:integer
-
# UUID type
-
when 'uuid'
-
52
:uuid
-
# JSON type
-
when 'json'
-
:json
-
# Small and big integer types
-
when /^(?:small|big)int$/
-
160
:integer
-
# Pass through all types that are not specific to PostgreSQL.
-
else
-
32275
super
-
end
-
end
-
end
-
-
# The PostgreSQL adapter works with the native C (https://bitbucket.org/ged/ruby-pg) driver.
-
#
-
# Options:
-
#
-
# * <tt>:host</tt> - Defaults to a Unix-domain socket in /tmp. On machines without Unix-domain sockets,
-
# the default is to connect to localhost.
-
# * <tt>:port</tt> - Defaults to 5432.
-
# * <tt>:username</tt> - Defaults to be the same as the operating system name of the user running the application.
-
# * <tt>:password</tt> - Password to be used if the server demands password authentication.
-
# * <tt>:database</tt> - Defaults to be the same as the user name.
-
# * <tt>:schema_search_path</tt> - An optional schema search path for the connection given
-
# as a string of comma-separated schema names. This is backward-compatible with the <tt>:schema_order</tt> option.
-
# * <tt>:encoding</tt> - An optional client encoding that is used in a <tt>SET client_encoding TO
-
# <encoding></tt> call on the connection.
-
# * <tt>:min_messages</tt> - An optional client min messages that is used in a
-
# <tt>SET client_min_messages TO <min_messages></tt> call on the connection.
-
# * <tt>:insert_returning</tt> - An optional boolean to control the use or <tt>RETURNING</tt> for <tt>INSERT</tt> statements
-
# defaults to true.
-
#
-
# Any further options are used as connection parameters to libpq. See
-
# http://www.postgresql.org/docs/9.1/static/libpq-connect.html for the
-
# list of parameters.
-
#
-
# In addition, default connection parameters of libpq can be set per environment variables.
-
# See http://www.postgresql.org/docs/9.1/static/libpq-envars.html .
-
1
class PostgreSQLAdapter < AbstractAdapter
-
1
class ColumnDefinition < ActiveRecord::ConnectionAdapters::ColumnDefinition
-
1
attr_accessor :array
-
end
-
-
1
class TableDefinition < ActiveRecord::ConnectionAdapters::TableDefinition
-
1
def xml(*args)
-
options = args.extract_options!
-
column(args[0], 'xml', options)
-
end
-
-
1
def tsvector(*args)
-
options = args.extract_options!
-
column(args[0], 'tsvector', options)
-
end
-
-
1
def hstore(name, options = {})
-
24
column(name, 'hstore', options)
-
end
-
-
1
def inet(name, options = {})
-
column(name, 'inet', options)
-
end
-
-
1
def cidr(name, options = {})
-
column(name, 'cidr', options)
-
end
-
-
1
def macaddr(name, options = {})
-
column(name, 'macaddr', options)
-
end
-
-
1
def uuid(name, options = {})
-
column(name, 'uuid', options)
-
end
-
-
1
def json(name, options = {})
-
6
column(name, 'json', options)
-
end
-
-
1
def column(name, type = nil, options = {})
-
1129
super
-
1127
column = self[name]
-
1127
column.array = options[:array]
-
-
1127
self
-
end
-
-
1
private
-
-
1
def new_column_definition(base, name, type)
-
1127
definition = ColumnDefinition.new base, name, type
-
1127
@columns << definition
-
1127
@columns_hash[name] = definition
-
1127
definition
-
end
-
end
-
-
1
ADAPTER_NAME = 'PostgreSQL'
-
-
1
NATIVE_DATABASE_TYPES = {
-
primary_key: "serial primary key",
-
string: { name: "character varying", limit: 255 },
-
text: { name: "text" },
-
integer: { name: "integer" },
-
float: { name: "float" },
-
decimal: { name: "decimal" },
-
datetime: { name: "timestamp" },
-
timestamp: { name: "timestamp" },
-
time: { name: "time" },
-
date: { name: "date" },
-
binary: { name: "bytea" },
-
boolean: { name: "boolean" },
-
xml: { name: "xml" },
-
tsvector: { name: "tsvector" },
-
hstore: { name: "hstore" },
-
inet: { name: "inet" },
-
cidr: { name: "cidr" },
-
macaddr: { name: "macaddr" },
-
uuid: { name: "uuid" },
-
json: { name: "json" }
-
}
-
-
1
include Quoting
-
1
include ReferentialIntegrity
-
1
include SchemaStatements
-
1
include DatabaseStatements
-
-
# Returns 'PostgreSQL' as adapter name for identification purposes.
-
1
def adapter_name
-
39
ADAPTER_NAME
-
end
-
-
# Adds `:array` option to the default set provided by the
-
# AbstractAdapter
-
1
def prepare_column_options(column, types)
-
9922
spec = super
-
9922
spec[:array] = 'true' if column.respond_to?(:array) && column.array
-
9922
spec
-
end
-
-
# Adds `:array` as a valid migration key
-
1
def migration_keys
-
3657
super + [:array]
-
end
-
-
# Returns +true+, since this connection adapter supports prepared statement
-
# caching.
-
1
def supports_statement_cache?
-
3
true
-
end
-
-
1
def supports_index_sort_order?
-
71
true
-
end
-
-
1
def supports_partial_index?
-
65
true
-
end
-
-
1
def supports_transaction_isolation?
-
7
true
-
end
-
-
1
class StatementPool < ConnectionAdapters::StatementPool
-
1
def initialize(connection, max)
-
97
super
-
97
@counter = 0
-
173
@cache = Hash.new { |h,pid| h[pid] = {} }
-
end
-
-
1
def each(&block); cache.each(&block); end
-
7835
def key?(key); cache.key?(key); end
-
7836
def [](key); cache[key]; end
-
1
def length; cache.length; end
-
-
1
def next_key
-
1420
"a#{@counter + 1}"
-
end
-
-
1
def []=(sql, key)
-
1422
while @max <= cache.size
-
dealloc(cache.shift.last)
-
end
-
1422
@counter += 1
-
1422
cache[sql] = key
-
end
-
-
1
def clear
-
510
cache.each_value do |stmt_key|
-
1382
dealloc stmt_key
-
end
-
510
cache.clear
-
end
-
-
1
def delete(sql_key)
-
1
dealloc cache[sql_key]
-
1
cache.delete sql_key
-
end
-
-
1
private
-
-
1
def cache
-
19535
@cache[Process.pid]
-
end
-
-
1
def dealloc(key)
-
1383
@connection.query "DEALLOCATE #{key}" if connection_active?
-
end
-
-
1
def connection_active?
-
1383
@connection.status == PGconn::CONNECTION_OK
-
rescue PGError
-
false
-
end
-
end
-
-
1
class BindSubstitution < Arel::Visitors::PostgreSQL # :nodoc:
-
1
include Arel::Visitors::BindVisitor
-
end
-
-
# Initializes and connects a PostgreSQL adapter.
-
1
def initialize(connection, logger, connection_parameters, config)
-
95
super(connection, logger)
-
-
190
if config.fetch(:prepared_statements) { true }
-
95
@visitor = Arel::Visitors::PostgreSQL.new self
-
else
-
@visitor = BindSubstitution.new self
-
end
-
-
95
connection_parameters.delete :prepared_statements
-
-
95
@connection_parameters, @config = connection_parameters, config
-
-
# @local_tz is initialized as nil to avoid warnings when connect tries to use it
-
95
@local_tz = nil
-
95
@table_alias_length = nil
-
-
95
connect
-
95
@statements = StatementPool.new @connection,
-
95
config.fetch(:statement_limit) { 1000 }
-
-
95
if postgresql_version < 80200
-
raise "Your version of PostgreSQL (#{postgresql_version}) is too old, please upgrade!"
-
end
-
-
95
initialize_type_map
-
95
@local_tz = execute('SHOW TIME ZONE', 'SCHEMA').first["TimeZone"]
-
95
@use_insert_returning = @config.key?(:insert_returning) ? @config[:insert_returning] : true
-
end
-
-
# Clears the prepared statements cache.
-
1
def clear_cache!
-
509
@statements.clear
-
end
-
-
# Is this connection alive and ready for queries?
-
1
def active?
-
10151
@connection.query 'SELECT 1'
-
10149
true
-
rescue PGError
-
2
false
-
end
-
-
# Close then reopen the connection.
-
1
def reconnect!
-
6
super
-
6
@connection.reset
-
6
configure_connection
-
end
-
-
1
def reset!
-
clear_cache!
-
super
-
end
-
-
# Disconnects from the database if already connected. Otherwise, this
-
# method does nothing.
-
1
def disconnect!
-
73
super
-
74
@connection.close rescue nil
-
end
-
-
1
def native_database_types #:nodoc:
-
2772
NATIVE_DATABASE_TYPES
-
end
-
-
# Returns true, since this connection adapter supports migrations.
-
1
def supports_migrations?
-
69
true
-
end
-
-
# Does PostgreSQL support finding primary key on non-Active Record tables?
-
1
def supports_primary_key? #:nodoc:
-
3
true
-
end
-
-
# Enable standard-conforming strings if available.
-
1
def set_standard_conforming_strings
-
101
old, self.client_min_messages = client_min_messages, 'panic'
-
101
execute('SET standard_conforming_strings = on', 'SCHEMA') rescue nil
-
ensure
-
101
self.client_min_messages = old
-
end
-
-
1
def supports_insert_with_returning?
-
true
-
end
-
-
1
def supports_ddl_transactions?
-
66
true
-
end
-
-
# Returns true, since this connection adapter supports savepoints.
-
1
def supports_savepoints?
-
19
true
-
end
-
-
# Returns true.
-
1
def supports_explain?
-
2
true
-
end
-
-
# Returns the configured supported identifier length supported by PostgreSQL
-
1
def table_alias_length
-
201
@table_alias_length ||= query('SHOW max_identifier_length', 'SCHEMA')[0][0].to_i
-
end
-
-
1
def add_column_options!(sql, options)
-
892
if options[:array] || options[:column].try(:array)
-
10
sql << '[]'
-
end
-
892
super
-
end
-
-
# Set the authorized user for this session
-
1
def session_auth=(user)
-
67
clear_cache!
-
67
exec_query "SET SESSION AUTHORIZATION #{user}"
-
end
-
-
1
module Utils
-
1
extend self
-
-
# Returns an array of <tt>[schema_name, table_name]</tt> extracted from +name+.
-
# +schema_name+ is nil if not specified in +name+.
-
# +schema_name+ and +table_name+ exclude surrounding quotes (regardless of whether provided in +name+)
-
# +name+ supports the range of schema/table references understood by PostgreSQL, for example:
-
#
-
# * <tt>table_name</tt>
-
# * <tt>"table.name"</tt>
-
# * <tt>schema_name.table_name</tt>
-
# * <tt>schema_name."table.name"</tt>
-
# * <tt>"schema.name"."table name"</tt>
-
1
def extract_schema_and_table(name)
-
1765
table, schema = name.scan(/[^".\s]+|"[^"]*"/)[0..1].collect{|m| m.gsub(/(^"|"$)/,'') }.reverse
-
874
[schema, table]
-
end
-
end
-
-
1
def use_insert_returning?
-
4782
@use_insert_returning
-
end
-
-
1
protected
-
-
# Returns the version of the connected PostgreSQL server.
-
1
def postgresql_version
-
190
@connection.server_version
-
end
-
-
# See http://www.postgresql.org/docs/9.1/static/errcodes-appendix.html
-
1
FOREIGN_KEY_VIOLATION = "23503"
-
1
UNIQUE_VIOLATION = "23505"
-
-
1
def translate_exception(exception, message)
-
442
case exception.result.try(:error_field, PGresult::PG_DIAG_SQLSTATE)
-
when UNIQUE_VIOLATION
-
2
RecordNotUnique.new(message, exception)
-
when FOREIGN_KEY_VIOLATION
-
1
InvalidForeignKey.new(message, exception)
-
else
-
439
super
-
end
-
end
-
-
1
private
-
-
1
def initialize_type_map
-
95
result = execute('SELECT oid, typname, typelem, typdelim, typinput FROM pg_type', 'SCHEMA')
-
72502
leaves, nodes = result.partition { |row| row['typelem'] == '0' }
-
-
# populate the leaf nodes
-
52557
leaves.find_all { |row| OID.registered_type? row['typname'] }.each do |row|
-
3129
OID::TYPE_MAP[row['oid'].to_i] = OID::NAMES[row['typname']]
-
end
-
-
20040
arrays, nodes = nodes.partition { |row| row['typinput'] == 'array_in' }
-
-
# populate composite types
-
760
nodes.find_all { |row| OID::TYPE_MAP.key? row['typelem'].to_i }.each do |row|
-
663
vector = OID::Vector.new row['typdelim'], OID::TYPE_MAP[row['typelem'].to_i]
-
663
OID::TYPE_MAP[row['oid'].to_i] = vector
-
end
-
-
# populate array types
-
19375
arrays.find_all { |row| OID::TYPE_MAP.key? row['typelem'].to_i }.each do |row|
-
3513
array = OID::Array.new OID::TYPE_MAP[row['typelem'].to_i]
-
3513
OID::TYPE_MAP[row['oid'].to_i] = array
-
end
-
end
-
-
1
FEATURE_NOT_SUPPORTED = "0A000" # :nodoc:
-
-
1
def exec_no_cache(sql, binds)
-
16364
@connection.async_exec(sql)
-
end
-
-
1
def exec_cache(sql, binds)
-
7833
begin
-
7834
stmt_key = prepare_statement sql
-
-
# Clear the queue
-
7834
@connection.get_last_result
-
7834
@connection.send_query_prepared(stmt_key, binds.map { |col, val|
-
11677
type_cast(val, col)
-
})
-
7834
@connection.block
-
7834
@connection.get_last_result
-
1
rescue PGError => e
-
# Get the PG code for the failure. Annoyingly, the code for
-
# prepared statements whose return value may have changed is
-
# FEATURE_NOT_SUPPORTED. Check here for more details:
-
# http://git.postgresql.org/gitweb/?p=postgresql.git;a=blob;f=src/backend/utils/cache/plancache.c#l573
-
1
begin
-
1
code = e.result.result_error_field(PGresult::PG_DIAG_SQLSTATE)
-
rescue
-
raise e
-
end
-
1
if FEATURE_NOT_SUPPORTED == code
-
1
@statements.delete sql_key(sql)
-
1
retry
-
else
-
raise e
-
end
-
end
-
end
-
-
# Returns the statement identifier for the client side cache
-
# of statements
-
1
def sql_key(sql)
-
7835
"#{schema_search_path}-#{sql}"
-
end
-
-
# Prepare the statement if it hasn't been prepared, return
-
# the statement key.
-
1
def prepare_statement(sql)
-
7834
sql_key = sql_key(sql)
-
7834
unless @statements.key? sql_key
-
1420
nextkey = @statements.next_key
-
1420
@connection.prepare nextkey, sql
-
1420
@statements[sql_key] = nextkey
-
end
-
7834
@statements[sql_key]
-
end
-
-
# The internal PostgreSQL identifier of the money data type.
-
1
MONEY_COLUMN_TYPE_OID = 790 #:nodoc:
-
# The internal PostgreSQL identifier of the BYTEA data type.
-
1
BYTEA_COLUMN_TYPE_OID = 17 #:nodoc:
-
-
# Connects to a PostgreSQL server and sets up the adapter depending on the
-
# connected server's characteristics.
-
1
def connect
-
95
@connection = PGconn.connect(@connection_parameters)
-
-
# Money type has a fixed precision of 10 in PostgreSQL 8.2 and below, and as of
-
# PostgreSQL 8.3 it has a fixed precision of 19. PostgreSQLColumn.extract_precision
-
# should know about this but can't detect it there, so deal with it here.
-
95
PostgreSQLColumn.money_precision = (postgresql_version >= 80300) ? 19 : 10
-
-
95
configure_connection
-
end
-
-
# Configures the encoding, verbosity, schema search path, and time zone of the connection.
-
# This is called by #connect and should not be called manually.
-
1
def configure_connection
-
101
if @config[:encoding]
-
@connection.set_client_encoding(@config[:encoding])
-
end
-
101
self.client_min_messages = @config[:min_messages] || 'warning'
-
101
self.schema_search_path = @config[:schema_search_path] || @config[:schema_order]
-
-
# Use standard-conforming strings if available so we don't have to do the E'...' dance.
-
101
set_standard_conforming_strings
-
-
# If using Active Record's time zone support configure the connection to return
-
# TIMESTAMP WITH ZONE types in UTC.
-
101
if ActiveRecord::Base.default_timezone == :utc
-
74
execute("SET time zone 'UTC'", 'SCHEMA')
-
27
elsif @local_tz
-
3
execute("SET time zone '#{@local_tz}'", 'SCHEMA')
-
end
-
end
-
-
# Returns the current ID of a table's sequence.
-
1
def last_insert_id(sequence_name) #:nodoc:
-
Integer(last_insert_id_value(sequence_name))
-
end
-
-
1
def last_insert_id_value(sequence_name)
-
1
last_insert_id_result(sequence_name).rows.first.first
-
end
-
-
1
def last_insert_id_result(sequence_name) #:nodoc:
-
3
exec_query("SELECT currval('#{sequence_name}')", 'SQL')
-
end
-
-
# Executes a SELECT query and returns the results, performing any data type
-
# conversions that are required to be performed here instead of in PostgreSQLColumn.
-
1
def select(sql, name = nil, binds = [])
-
8950
exec_query(sql, name, binds)
-
end
-
-
1
def select_raw(sql, name = nil)
-
8
res = execute(sql, name)
-
8
results = result_as_array(res)
-
8
fields = res.fields
-
8
res.clear
-
8
return fields, results
-
end
-
-
# Returns the list of a table's column names, data types, and default values.
-
#
-
# The underlying query is roughly:
-
# SELECT column.name, column.type, default.value
-
# FROM column LEFT JOIN default
-
# ON column.table_id = default.table_id
-
# AND column.num = default.column_num
-
# WHERE column.table_id = get_table_id('table_name')
-
# AND column.num > 0
-
# AND NOT column.is_dropped
-
# ORDER BY column.num
-
#
-
# If the table name is not prefixed with a schema, the database will
-
# take the first match from the schema search path.
-
#
-
# Query implementation notes:
-
# - format_type includes the column size constraint, e.g. varchar(50)
-
# - ::regclass is a function that gives the id for a table name
-
1
def column_definitions(table_name) #:nodoc:
-
9130
exec_query(<<-end_sql, 'SCHEMA').rows
-
SELECT a.attname, format_type(a.atttypid, a.atttypmod),
-
pg_get_expr(d.adbin, d.adrelid), a.attnotnull, a.atttypid, a.atttypmod
-
FROM pg_attribute a LEFT JOIN pg_attrdef d
-
ON a.attrelid = d.adrelid AND a.attnum = d.adnum
-
WHERE a.attrelid = '#{quote_table_name(table_name)}'::regclass
-
AND a.attnum > 0 AND NOT a.attisdropped
-
ORDER BY a.attnum
-
end_sql
-
end
-
-
1
def extract_pg_identifier_from_name(name)
-
97664
match_data = name.start_with?('"') ? name.match(/\"([^\"]+)\"/) : name.match(/([^\.]+)/)
-
-
97664
if match_data
-
97664
rest = name[match_data[0].length, name.length]
-
97664
rest = rest[1, rest.length] if rest.start_with? "."
-
97664
[match_data[1], (rest.length > 0 ? rest : nil)]
-
end
-
end
-
-
1
def extract_table_ref_from_insert_sql(sql)
-
249
sql[/into\s+([^\(]*).*values\s*\(/i]
-
249
$1.strip if $1
-
end
-
-
1
def table_definition
-
375
TableDefinition.new(self)
-
end
-
end
-
end
-
end
-
1
module ActiveRecord
-
1
module ConnectionAdapters
-
1
class SchemaCache
-
1
attr_reader :columns, :columns_hash, :primary_keys, :tables, :version
-
1
attr_accessor :connection
-
-
1
def initialize(conn)
-
119
@connection = conn
-
-
119
@columns = {}
-
119
@columns_hash = {}
-
119
@primary_keys = {}
-
119
@tables = {}
-
119
prepare_default_proc
-
end
-
-
# A cached lookup for table existence.
-
1
def table_exists?(name)
-
24537
return @tables[name] if @tables.key? name
-
-
499
@tables[name] = connection.table_exists?(name)
-
end
-
-
# Add internal cache for table with +table_name+.
-
1
def add(table_name)
-
if table_exists?(table_name)
-
@primary_keys[table_name]
-
@columns[table_name]
-
@columns_hash[table_name]
-
end
-
end
-
-
# Clears out internal caches
-
1
def clear!
-
2
@columns.clear
-
2
@columns_hash.clear
-
2
@primary_keys.clear
-
2
@tables.clear
-
2
@version = nil
-
end
-
-
# Clear out internal caches for table with +table_name+.
-
1
def clear_table_cache!(table_name)
-
127
@columns.delete table_name
-
127
@columns_hash.delete table_name
-
127
@primary_keys.delete table_name
-
127
@tables.delete table_name
-
end
-
-
1
def marshal_dump
-
# if we get current version during initialization, it happens stack over flow.
-
1
@version = ActiveRecord::Migrator.current_version
-
[@version] + [:@columns, :@columns_hash, :@primary_keys, :@tables].map do |val|
-
8
self.instance_variable_get(val).inject({}) { |h, v| h[v[0]] = v[1]; h }
-
1
end
-
end
-
-
1
def marshal_load(array)
-
1
@version, @columns, @columns_hash, @primary_keys, @tables = array
-
1
prepare_default_proc
-
end
-
-
1
private
-
-
1
def prepare_default_proc
-
120
@columns.default_proc = Proc.new do |h, table_name|
-
421
h[table_name] = connection.columns(table_name)
-
end
-
-
120
@columns_hash.default_proc = Proc.new do |h, table_name|
-
325
h[table_name] = Hash[columns[table_name].map { |col|
-
1587
[col.name, col]
-
}]
-
end
-
-
120
@primary_keys.default_proc = Proc.new do |h, table_name|
-
155
h[table_name] = table_exists?(table_name) ? connection.primary_key(table_name) : nil
-
end
-
end
-
end
-
end
-
end
-
1
module ActiveRecord
-
1
module ConnectionAdapters
-
1
class StatementPool
-
1
include Enumerable
-
-
1
def initialize(connection, max = 1000)
-
97
@connection = connection
-
97
@max = max
-
end
-
-
1
def each
-
raise NotImplementedError
-
end
-
-
1
def key?(key)
-
raise NotImplementedError
-
end
-
-
1
def [](key)
-
raise NotImplementedError
-
end
-
-
1
def length
-
raise NotImplementedError
-
end
-
-
1
def []=(sql, key)
-
raise NotImplementedError
-
end
-
-
1
def clear
-
raise NotImplementedError
-
end
-
-
1
def delete(key)
-
raise NotImplementedError
-
end
-
end
-
end
-
end
-
1
module ActiveRecord
-
1
module ConnectionHandling
-
# Establishes the connection to the database. Accepts a hash as input where
-
# the <tt>:adapter</tt> key must be specified with the name of a database adapter (in lower-case)
-
# example for regular databases (MySQL, Postgresql, etc):
-
#
-
# ActiveRecord::Base.establish_connection(
-
# :adapter => "mysql",
-
# :host => "localhost",
-
# :username => "myuser",
-
# :password => "mypass",
-
# :database => "somedatabase"
-
# )
-
#
-
# Example for SQLite database:
-
#
-
# ActiveRecord::Base.establish_connection(
-
# :adapter => "sqlite",
-
# :database => "path/to/dbfile"
-
# )
-
#
-
# Also accepts keys as strings (for parsing from YAML for example):
-
#
-
# ActiveRecord::Base.establish_connection(
-
# "adapter" => "sqlite",
-
# "database" => "path/to/dbfile"
-
# )
-
#
-
# Or a URL:
-
#
-
# ActiveRecord::Base.establish_connection(
-
# "postgres://myuser:mypass@localhost/somedatabase"
-
# )
-
#
-
# The exceptions AdapterNotSpecified, AdapterNotFound and ArgumentError
-
# may be returned on an error.
-
1
def establish_connection(spec = ENV["DATABASE_URL"])
-
25
resolver = ConnectionAdapters::ConnectionSpecification::Resolver.new spec, configurations
-
25
spec = resolver.spec
-
-
25
unless respond_to?(spec.adapter_method)
-
raise AdapterNotFound, "database configuration specifies nonexistent #{spec.config[:adapter]} adapter"
-
end
-
-
25
remove_connection
-
25
connection_handler.establish_connection self, spec
-
end
-
-
# Returns the connection currently associated with the class. This can
-
# also be used to "borrow" the connection to do database work unrelated
-
# to any of the specific Active Records.
-
1
def connection
-
43359
retrieve_connection
-
end
-
-
1
def connection_id
-
94832
Thread.current['ActiveRecord::Base.connection_id']
-
end
-
-
1
def connection_id=(connection_id)
-
32
Thread.current['ActiveRecord::Base.connection_id'] = connection_id
-
end
-
-
# Returns the configuration of the associated connection as a hash:
-
#
-
# ActiveRecord::Base.connection_config
-
# # => {:pool=>5, :timeout=>5000, :database=>"db/development.sqlite3", :adapter=>"sqlite3"}
-
#
-
# Please use only for reading.
-
1
def connection_config
-
1
connection_pool.spec.config
-
end
-
-
1
def connection_pool
-
122
connection_handler.retrieve_connection_pool(self) or raise ConnectionNotEstablished
-
end
-
-
1
def retrieve_connection
-
43379
connection_handler.retrieve_connection(self)
-
end
-
-
# Returns true if Active Record is connected.
-
1
def connected?
-
175
connection_handler.connected?(self)
-
end
-
-
1
def remove_connection(klass = self)
-
32
connection_handler.remove_connection(klass)
-
end
-
-
1
def clear_cache! # :nodoc:
-
1
connection.schema_cache.clear!
-
end
-
-
1
delegate :clear_active_connections!, :clear_reloadable_connections!,
-
:clear_all_connections!, :to => :connection_handler
-
end
-
end
-
1
require 'active_support/core_ext/hash/indifferent_access'
-
1
require 'active_support/core_ext/object/duplicable'
-
1
require 'thread'
-
-
1
module ActiveRecord
-
1
module Core
-
1
extend ActiveSupport::Concern
-
-
1
included do
-
##
-
# :singleton-method:
-
#
-
# Accepts a logger conforming to the interface of Log4r which is then
-
# passed on to any new database connections made and which can be
-
# retrieved on both a class and instance level by calling +logger+.
-
1
mattr_accessor :logger, instance_writer: false
-
-
##
-
# :singleton-method:
-
# Contains the database configuration - as is typically stored in config/database.yml -
-
# as a Hash.
-
#
-
# For example, the following database.yml...
-
#
-
# development:
-
# adapter: sqlite3
-
# database: db/development.sqlite3
-
#
-
# production:
-
# adapter: sqlite3
-
# database: db/production.sqlite3
-
#
-
# ...would result in ActiveRecord::Base.configurations to look like this:
-
#
-
# {
-
# 'development' => {
-
# 'adapter' => 'sqlite3',
-
# 'database' => 'db/development.sqlite3'
-
# },
-
# 'production' => {
-
# 'adapter' => 'sqlite3',
-
# 'database' => 'db/production.sqlite3'
-
# }
-
# }
-
1
mattr_accessor :configurations, instance_writer: false
-
1
self.configurations = {}
-
-
##
-
# :singleton-method:
-
# Determines whether to use Time.utc (using :utc) or Time.local (using :local) when pulling
-
# dates and times from the database. This is set to :utc by default.
-
1
mattr_accessor :default_timezone, instance_writer: false
-
1
self.default_timezone = :utc
-
-
##
-
# :singleton-method:
-
# Specifies the format to use when dumping the database schema with Rails'
-
# Rakefile. If :sql, the schema is dumped as (potentially database-
-
# specific) SQL statements. If :ruby, the schema is dumped as an
-
# ActiveRecord::Schema file which can be loaded into any database that
-
# supports migrations. Use :ruby if you want to have different database
-
# adapters for, e.g., your development and test environments.
-
1
mattr_accessor :schema_format, instance_writer: false
-
1
self.schema_format = :ruby
-
-
##
-
# :singleton-method:
-
# Specify whether or not to use timestamps for migration versions
-
1
mattr_accessor :timestamped_migrations, instance_writer: false
-
1
self.timestamped_migrations = true
-
-
1
class_attribute :connection_handler, instance_writer: false
-
1
self.connection_handler = ConnectionAdapters::ConnectionHandler.new
-
end
-
-
1
module ClassMethods
-
1
def inherited(child_class) #:nodoc:
-
486
child_class.initialize_generated_modules
-
486
super
-
end
-
-
1
def initialize_generated_modules
-
486
@attribute_methods_mutex = Mutex.new
-
-
# force attribute methods to be higher in inheritance hierarchy than other generated methods
-
486
generated_attribute_methods
-
486
generated_feature_methods
-
end
-
-
1
def generated_feature_methods
-
@generated_feature_methods ||= begin
-
486
mod = const_set(:GeneratedFeatureMethods, Module.new)
-
486
include mod
-
486
mod
-
2851
end
-
end
-
-
# Returns a string like 'Post(id:integer, title:string, body:text)'
-
1
def inspect
-
45
if self == Base
-
1
super
-
44
elsif abstract_class?
-
4
"#{super}(abstract)"
-
40
elsif table_exists?
-
605
attr_list = columns.map { |c| "#{c.name}: #{c.type}" } * ', '
-
39
"#{super}(#{attr_list})"
-
else
-
1
"#{super}(Table doesn't exist)"
-
end
-
end
-
-
# Overwrite the default class equality method to provide support for association proxies.
-
1
def ===(object)
-
5045
object.is_a?(self)
-
end
-
-
# Returns an instance of <tt>Arel::Table</tt> loaded with the current table name.
-
#
-
# class Post < ActiveRecord::Base
-
# scope :published_and_commented, published.and(self.arel_table[:comments_count].gt(0))
-
# end
-
1
def arel_table
-
44799
@arel_table ||= Arel::Table.new(table_name, arel_engine)
-
end
-
-
# Returns the Arel engine.
-
1
def arel_engine
-
@arel_engine ||= begin
-
479
if Base == self || connection_handler.retrieve_connection_pool(self)
-
478
self
-
else
-
1
superclass.arel_engine
-
end
-
1221
end
-
end
-
-
1
private
-
-
1
def relation #:nodoc:
-
21896
relation = Relation.new(self, arel_table)
-
-
21896
if finder_needs_type_condition?
-
2688
relation.where(type_condition).create_with(inheritance_column.to_sym => sti_name)
-
else
-
19208
relation
-
end
-
end
-
end
-
-
# New objects can be instantiated as either empty (pass no construction parameter) or pre-set with
-
# attributes but not yet saved (pass a hash with key names matching the associated table column names).
-
# In both instances, valid attribute keys are determined by the column names of the associated table --
-
# hence you can't have attributes that aren't part of the table columns.
-
#
-
# ==== Example:
-
# # Instantiates a single new object
-
# User.new(:first_name => 'Jamie')
-
1
def initialize(attributes = nil)
-
2967
defaults = self.class.column_defaults.dup
-
23729
defaults.each { |k, v| defaults[k] = v.dup if v.duplicable? }
-
-
2966
@attributes = self.class.initialize_attributes(defaults)
-
2966
@columns_hash = self.class.column_types.dup
-
-
2966
init_internals
-
2966
ensure_proper_type
-
2966
populate_with_current_scope_attributes
-
-
2966
assign_attributes(attributes) if attributes
-
-
2962
yield self if block_given?
-
2962
run_callbacks :initialize unless _initialize_callbacks.empty?
-
end
-
-
# Initialize an empty model object from +coder+. +coder+ must contain
-
# the attributes necessary for initializing an empty model object. For
-
# example:
-
#
-
# class Post < ActiveRecord::Base
-
# end
-
#
-
# post = Post.allocate
-
# post.init_with('attributes' => { 'title' => 'hello world' })
-
# post.title # => 'hello world'
-
1
def init_with(coder)
-
10724
@attributes = self.class.initialize_attributes(coder['attributes'])
-
10724
@columns_hash = self.class.column_types.merge(coder['column_types'] || {})
-
-
10724
init_internals
-
-
10724
@new_record = false
-
-
10724
run_callbacks :find
-
10724
run_callbacks :initialize
-
-
10724
self
-
end
-
-
##
-
# :method: clone
-
# Identical to Ruby's clone method. This is a "shallow" copy. Be warned that your attributes are not copied.
-
# That means that modifying attributes of the clone will modify the original, since they will both point to the
-
# same attributes hash. If you need a copy of your attributes hash, please use the #dup method.
-
#
-
# user = User.first
-
# new_user = user.clone
-
# user.name # => "Bob"
-
# new_user.name = "Joe"
-
# user.name # => "Joe"
-
#
-
# user.object_id == new_user.object_id # => false
-
# user.name.object_id == new_user.name.object_id # => true
-
#
-
# user.name.object_id == user.dup.name.object_id # => false
-
-
##
-
# :method: dup
-
# Duped objects have no id assigned and are treated as new records. Note
-
# that this is a "shallow" copy as it copies the object's attributes
-
# only, not its associations. The extent of a "deep" copy is application
-
# specific and is therefore left to the application to implement according
-
# to its need.
-
# The dup method does not preserve the timestamps (created|updated)_(at|on).
-
-
##
-
1
def initialize_dup(other) # :nodoc:
-
25
cloned_attributes = other.clone_attributes(:read_attribute_before_type_cast)
-
25
self.class.initialize_attributes(cloned_attributes, :serialized => false)
-
-
25
@attributes = cloned_attributes
-
25
@attributes[self.class.primary_key] = nil
-
-
25
run_callbacks(:initialize) unless _initialize_callbacks.empty?
-
-
25
@changed_attributes = {}
-
25
self.class.column_defaults.each do |attr, orig_value|
-
330
@changed_attributes[attr] = orig_value if _field_changed?(attr, orig_value, @attributes[attr])
-
end
-
-
25
@aggregation_cache = {}
-
25
@association_cache = {}
-
25
@attributes_cache = {}
-
-
25
@new_record = true
-
-
25
ensure_proper_type
-
25
populate_with_current_scope_attributes
-
25
super
-
end
-
-
# Populate +coder+ with attributes about this record that should be
-
# serialized. The structure of +coder+ defined in this method is
-
# guaranteed to match the structure of +coder+ passed to the +init_with+
-
# method.
-
#
-
# Example:
-
#
-
# class Post < ActiveRecord::Base
-
# end
-
# coder = {}
-
# Post.new.encode_with(coder)
-
# coder # => {"attributes" => {"id" => nil, ... }}
-
1
def encode_with(coder)
-
6
coder['attributes'] = attributes
-
end
-
-
# Returns true if +comparison_object+ is the same exact object, or +comparison_object+
-
# is of the same type and +self+ has an ID and it is equal to +comparison_object.id+.
-
#
-
# Note that new records are different from any other record by definition, unless the
-
# other record is the receiver itself. Besides, if you fetch existing records with
-
# +select+ and leave the ID out, you're on your own, this predicate will return false.
-
#
-
# Note also that destroying a record preserves its ID in the model instance, so deleted
-
# models are still comparable.
-
1
def ==(comparison_object)
-
super ||
-
comparison_object.instance_of?(self.class) &&
-
id.present? &&
-
6762
comparison_object.id == id
-
end
-
1
alias :eql? :==
-
-
# Delegates to id in order to allow two records of the same type and id to work with something like:
-
# [ Person.find(1), Person.find(2), Person.find(3) ] & [ Person.find(1), Person.find(4) ] # => [ Person.find(1) ]
-
1
def hash
-
14400
id.hash
-
end
-
-
# Freeze the attributes hash such that associations are still accessible, even on destroyed records.
-
1
def freeze
-
255
@attributes.freeze
-
255
self
-
end
-
-
# Returns +true+ if the attributes hash has been frozen.
-
1
def frozen?
-
36
@attributes.frozen?
-
end
-
-
# Allows sort on objects
-
1
def <=>(other_object)
-
2
if other_object.is_a?(self.class)
-
1
self.to_key <=> other_object.to_key
-
end
-
end
-
-
# Returns +true+ if the record is read only. Records loaded through joins with piggy-back
-
# attributes will be marked as read only since they cannot be saved.
-
1
def readonly?
-
3390
@readonly
-
end
-
-
# Marks this record as read only.
-
1
def readonly!
-
176
@readonly = true
-
end
-
-
# Returns the connection currently associated with the class. This can
-
# also be used to "borrow" the connection to do database work that isn't
-
# easily done without going straight to SQL.
-
1
def connection
-
590
self.class.connection
-
end
-
-
# Returns the contents of the record as a nicely formatted string.
-
1
def inspect
-
71
inspection = if @attributes
-
69
self.class.column_names.collect { |name|
-
801
if has_attribute?(name)
-
770
"#{name}: #{attribute_for_inspect(name)}"
-
end
-
}.compact.join(", ")
-
else
-
2
"not initialized"
-
end
-
71
"#<#{self.class} #{inspection}>"
-
end
-
-
# Returns a hash of the given methods with their names as keys and returned values as values.
-
1
def slice(*methods)
-
4
Hash[methods.map { |method| [method, public_send(method)] }].with_indifferent_access
-
end
-
-
1
private
-
-
# Under Ruby 1.9, Array#flatten will call #to_ary (recursively) on each of the elements
-
# of the array, and then rescues from the possible NoMethodError. If those elements are
-
# ActiveRecord::Base's, then this triggers the various method_missing's that we have,
-
# which significantly impacts upon performance.
-
#
-
# So we can avoid the method_missing hit by explicitly defining #to_ary as nil here.
-
#
-
# See also http://tenderlovemaking.com/2011/06/28/til-its-ok-to-return-nil-from-to_ary.html
-
1
def to_ary # :nodoc:
-
nil
-
end
-
-
1
def init_internals
-
13690
pk = self.class.primary_key
-
13690
@attributes[pk] = nil unless @attributes.key?(pk)
-
-
13690
@aggregation_cache = {}
-
13690
@association_cache = {}
-
13690
@attributes_cache = {}
-
13690
@previously_changed = {}
-
13690
@changed_attributes = {}
-
13690
@readonly = false
-
13690
@destroyed = false
-
13690
@marked_for_destruction = false
-
13690
@new_record = true
-
13690
@txn = nil
-
13690
@_start_transaction_state = {}
-
end
-
end
-
end
-
1
module ActiveRecord
-
# = Active Record Counter Cache
-
1
module CounterCache
-
1
extend ActiveSupport::Concern
-
-
1
module ClassMethods
-
# Resets one or more counter caches to their correct value using an SQL
-
# count query. This is useful when adding new counter caches, or if the
-
# counter has been corrupted or modified directly by SQL.
-
#
-
# ==== Parameters
-
#
-
# * +id+ - The id of the object you wish to reset a counter on.
-
# * +counters+ - One or more counter names to reset
-
#
-
# ==== Examples
-
#
-
# # For Post with id #1 records reset the comments_count
-
# Post.reset_counters(1, :comments)
-
1
def reset_counters(id, *counters)
-
10
object = find(id)
-
10
counters.each do |association|
-
10
has_many_association = reflect_on_association(association.to_sym)
-
-
10
if has_many_association.is_a? ActiveRecord::Reflection::ThroughReflection
-
2
has_many_association = has_many_association.through_reflection
-
end
-
-
10
foreign_key = has_many_association.foreign_key.to_s
-
10
child_class = has_many_association.klass
-
10
belongs_to = child_class.reflect_on_all_associations(:belongs_to)
-
22
reflection = belongs_to.find { |e| e.foreign_key.to_s == foreign_key && e.options[:counter_cache].present? }
-
10
counter_name = reflection.counter_cache_column
-
-
10
stmt = unscoped.where(arel_table[primary_key].eq(object.id)).arel.compile_update({
-
arel_table[counter_name] => object.send(association).count
-
})
-
10
connection.update stmt
-
end
-
10
return true
-
end
-
-
# A generic "counter updater" implementation, intended primarily to be
-
# used by increment_counter and decrement_counter, but which may also
-
# be useful on its own. It simply does a direct SQL update for the record
-
# with the given ID, altering the given hash of counters by the amount
-
# given by the corresponding value:
-
#
-
# ==== Parameters
-
#
-
# * +id+ - The id of the object you wish to update a counter on or an Array of ids.
-
# * +counters+ - An Array of Hashes containing the names of the fields
-
# to update as keys and the amount to update the field by as values.
-
#
-
# ==== Examples
-
#
-
# # For the Post with id of 5, decrement the comment_count by 1, and
-
# # increment the action_count by 1
-
# Post.update_counters 5, :comment_count => -1, :action_count => 1
-
# # Executes the following SQL:
-
# # UPDATE posts
-
# # SET comment_count = COALESCE(comment_count, 0) - 1,
-
# # action_count = COALESCE(action_count, 0) + 1
-
# # WHERE id = 5
-
#
-
# # For the Posts with id of 10 and 15, increment the comment_count by 1
-
# Post.update_counters [10, 15], :comment_count => 1
-
# # Executes the following SQL:
-
# # UPDATE posts
-
# # SET comment_count = COALESCE(comment_count, 0) + 1
-
# # WHERE id IN (10, 15)
-
1
def update_counters(id, counters)
-
144
updates = counters.map do |counter_name, value|
-
153
operator = value < 0 ? '-' : '+'
-
153
quoted_column = connection.quote_column_name(counter_name)
-
153
"#{quoted_column} = COALESCE(#{quoted_column}, 0) #{operator} #{value.abs}"
-
end
-
-
144
where(primary_key => id).update_all updates.join(', ')
-
end
-
-
# Increment a number field by one, usually representing a count.
-
#
-
# This is used for caching aggregate values, so that they don't need to be computed every time.
-
# For example, a DiscussionBoard may cache post_count and comment_count otherwise every time the board is
-
# shown it would have to run an SQL query to find how many posts and comments there are.
-
#
-
# ==== Parameters
-
#
-
# * +counter_name+ - The name of the field that should be incremented.
-
# * +id+ - The id of the object that should be incremented.
-
#
-
# ==== Examples
-
#
-
# # Increment the post_count column for the record with an id of 5
-
# DiscussionBoard.increment_counter(:post_count, 5)
-
1
def increment_counter(counter_name, id)
-
78
update_counters(id, counter_name => 1)
-
end
-
-
# Decrement a number field by one, usually representing a count.
-
#
-
# This works the same as increment_counter but reduces the column value by 1 instead of increasing it.
-
#
-
# ==== Parameters
-
#
-
# * +counter_name+ - The name of the field that should be decremented.
-
# * +id+ - The id of the object that should be decremented.
-
#
-
# ==== Examples
-
#
-
# # Decrement the post_count column for the record with an id of 5
-
# DiscussionBoard.decrement_counter(:post_count, 5)
-
1
def decrement_counter(counter_name, id)
-
25
update_counters(id, counter_name => -1)
-
end
-
end
-
end
-
end
-
1
module ActiveRecord
-
1
module DynamicMatchers #:nodoc:
-
# This code in this file seems to have a lot of indirection, but the indirection
-
# is there to provide extension points for the activerecord-deprecated_finders
-
# gem. When we stop supporting activerecord-deprecated_finders (from Rails 5),
-
# then we can remove the indirection.
-
-
1
def respond_to?(name, include_private = false)
-
28834
match = Method.match(self, name)
-
28834
match && match.valid? || super
-
end
-
-
1
private
-
-
1
def method_missing(name, *arguments, &block)
-
545
match = Method.match(self, name)
-
-
545
if match && match.valid?
-
85
match.define
-
85
send(name, *arguments, &block)
-
else
-
460
super
-
end
-
end
-
-
1
class Method
-
1
@matchers = []
-
-
1
class << self
-
1
attr_reader :matchers
-
-
1
def match(model, name)
-
264894
klass = matchers.find { |k| name =~ k.pattern }
-
29512
klass.new(model, name) if klass
-
end
-
-
1
def pattern
-
235554
/^#{prefix}_([_a-zA-Z]\w*)#{suffix}$/
-
end
-
-
1
def prefix
-
raise NotImplementedError
-
end
-
-
1
def suffix
-
176762
''
-
end
-
end
-
-
1
attr_reader :model, :name, :attribute_names
-
-
1
def initialize(model, name)
-
172
@model = model
-
172
@name = name.to_s
-
172
@attribute_names = @name.match(self.class.pattern)[1].split('_and_')
-
382
@attribute_names.map! { |n| @model.attribute_aliases[n] || n }
-
end
-
-
1
def valid?
-
262
attribute_names.all? { |name| model.columns_hash[name] || model.reflect_on_aggregation(name.to_sym) }
-
end
-
-
1
def define
-
85
model.class_eval <<-CODE, __FILE__, __LINE__ + 1
-
def self.#{name}(#{signature})
-
#{body}
-
end
-
CODE
-
end
-
-
1
def body
-
raise NotImplementedError
-
end
-
end
-
-
1
module Finder
-
# Extended in activerecord-deprecated_finders
-
1
def body
-
58
result
-
end
-
-
# Extended in activerecord-deprecated_finders
-
1
def result
-
58
"#{finder}(#{attributes_hash})"
-
end
-
-
# Extended in activerecord-deprecated_finders
-
1
def signature
-
62
attribute_names.join(', ')
-
end
-
-
1
def attributes_hash
-
136
"{" + attribute_names.map { |name| ":#{name} => #{name}" }.join(',') + "}"
-
end
-
-
1
def finder
-
raise NotImplementedError
-
end
-
end
-
-
1
class FindBy < Method
-
1
Method.matchers << self
-
1
include Finder
-
-
1
def self.prefix
-
29575
"find_by"
-
end
-
-
1
def finder
-
39
"find_by"
-
end
-
end
-
-
1
class FindByBang < Method
-
1
Method.matchers << self
-
1
include Finder
-
-
1
def self.prefix
-
29456
"find_by"
-
end
-
-
1
def self.suffix
-
29456
"!"
-
end
-
-
1
def finder
-
3
"find_by!"
-
end
-
end
-
end
-
end
-
1
module ActiveRecord
-
-
# = Active Record Errors
-
#
-
# Generic Active Record exception class.
-
1
class ActiveRecordError < StandardError
-
end
-
-
# Raised when the single-table inheritance mechanism fails to locate the subclass
-
# (for example due to improper usage of column that +inheritance_column+ points to).
-
1
class SubclassNotFound < ActiveRecordError #:nodoc:
-
end
-
-
# Raised when an object assigned to an association has an incorrect type.
-
#
-
# class Ticket < ActiveRecord::Base
-
# has_many :patches
-
# end
-
#
-
# class Patch < ActiveRecord::Base
-
# belongs_to :ticket
-
# end
-
#
-
# # Comments are not patches, this assignment raises AssociationTypeMismatch.
-
# @ticket.patches << Comment.new(:content => "Please attach tests to your patch.")
-
1
class AssociationTypeMismatch < ActiveRecordError
-
end
-
-
# Raised when unserialized object's type mismatches one specified for serializable field.
-
1
class SerializationTypeMismatch < ActiveRecordError
-
end
-
-
# Raised when adapter not specified on connection (or configuration file <tt>config/database.yml</tt>
-
# misses adapter field).
-
1
class AdapterNotSpecified < ActiveRecordError
-
end
-
-
# Raised when Active Record cannot find database adapter specified in <tt>config/database.yml</tt> or programmatically.
-
1
class AdapterNotFound < ActiveRecordError
-
end
-
-
# Raised when connection to the database could not been established (for example when <tt>connection=</tt>
-
# is given a nil object).
-
1
class ConnectionNotEstablished < ActiveRecordError
-
end
-
-
# Raised when Active Record cannot find record by given id or set of ids.
-
1
class RecordNotFound < ActiveRecordError
-
end
-
-
# Raised by ActiveRecord::Base.save! and ActiveRecord::Base.create! methods when record cannot be
-
# saved because record is invalid.
-
1
class RecordNotSaved < ActiveRecordError
-
end
-
-
# Raised by ActiveRecord::Base.destroy! when a call to destroy would return false.
-
1
class RecordNotDestroyed < ActiveRecordError
-
end
-
-
# Raised when SQL statement cannot be executed by the database (for example, it's often the case for
-
# MySQL when Ruby driver used is too old).
-
1
class StatementInvalid < ActiveRecordError
-
end
-
-
# Raised when SQL statement is invalid and the application gets a blank result.
-
1
class ThrowResult < ActiveRecordError
-
end
-
-
# Parent class for all specific exceptions which wrap database driver exceptions
-
# provides access to the original exception also.
-
1
class WrappedDatabaseException < StatementInvalid
-
1
attr_reader :original_exception
-
-
1
def initialize(message, original_exception)
-
3
super(message)
-
3
@original_exception = original_exception
-
end
-
end
-
-
# Raised when a record cannot be inserted because it would violate a uniqueness constraint.
-
1
class RecordNotUnique < WrappedDatabaseException
-
end
-
-
# Raised when a record cannot be inserted or updated because it references a non-existent record.
-
1
class InvalidForeignKey < WrappedDatabaseException
-
end
-
-
# Raised when number of bind variables in statement given to <tt>:condition</tt> key (for example,
-
# when using +find+ method)
-
# does not match number of expected variables.
-
#
-
# For example, in
-
#
-
# Location.where("lat = ? AND lng = ?", 53.7362)
-
#
-
# two placeholders are given but only one variable to fill them.
-
1
class PreparedStatementInvalid < ActiveRecordError
-
end
-
-
# Raised on attempt to save stale record. Record is stale when it's being saved in another query after
-
# instantiation, for example, when two users edit the same wiki page and one starts editing and saves
-
# the page before the other.
-
#
-
# Read more about optimistic locking in ActiveRecord::Locking module RDoc.
-
1
class StaleObjectError < ActiveRecordError
-
1
attr_reader :record, :attempted_action
-
-
1
def initialize(record, attempted_action)
-
9
super("Attempted to #{attempted_action} a stale object: #{record.class.name}")
-
9
@record = record
-
9
@attempted_action = attempted_action
-
end
-
-
end
-
-
# Raised when association is being configured improperly or
-
# user tries to use offset and limit together with has_many or has_and_belongs_to_many associations.
-
1
class ConfigurationError < ActiveRecordError
-
end
-
-
# Raised on attempt to update record that is instantiated as read only.
-
1
class ReadOnlyRecord < ActiveRecordError
-
end
-
-
# ActiveRecord::Transactions::ClassMethods.transaction uses this exception
-
# to distinguish a deliberate rollback from other exceptional situations.
-
# Normally, raising an exception will cause the +transaction+ method to rollback
-
# the database transaction *and* pass on the exception. But if you raise an
-
# ActiveRecord::Rollback exception, then the database transaction will be rolled back,
-
# without passing on the exception.
-
#
-
# For example, you could do this in your controller to rollback a transaction:
-
#
-
# class BooksController < ActionController::Base
-
# def create
-
# Book.transaction do
-
# book = Book.new(params[:book])
-
# book.save!
-
# if today_is_friday?
-
# # The system must fail on Friday so that our support department
-
# # won't be out of job. We silently rollback this transaction
-
# # without telling the user.
-
# raise ActiveRecord::Rollback, "Call tech support!"
-
# end
-
# end
-
# # ActiveRecord::Rollback is the only exception that won't be passed on
-
# # by ActiveRecord::Base.transaction, so this line will still be reached
-
# # even on Friday.
-
# redirect_to root_url
-
# end
-
# end
-
1
class Rollback < ActiveRecordError
-
end
-
-
# Raised when attribute has a name reserved by Active Record (when attribute has name of one of Active Record instance methods).
-
1
class DangerousAttributeError < ActiveRecordError
-
end
-
-
# Raised when unknown attributes are supplied via mass assignment.
-
1
class UnknownAttributeError < NoMethodError
-
end
-
-
# Raised when an error occurred while doing a mass assignment to an attribute through the
-
# <tt>attributes=</tt> method. The exception has an +attribute+ property that is the name of the
-
# offending attribute.
-
1
class AttributeAssignmentError < ActiveRecordError
-
1
attr_reader :exception, :attribute
-
1
def initialize(message, exception, attribute)
-
7
super(message)
-
7
@exception = exception
-
7
@attribute = attribute
-
end
-
end
-
-
# Raised when there are multiple errors while doing a mass assignment through the +attributes+
-
# method. The exception has an +errors+ property that contains an array of AttributeAssignmentError
-
# objects, each corresponding to the error while assigning to an attribute.
-
1
class MultiparameterAssignmentErrors < ActiveRecordError
-
1
attr_reader :errors
-
1
def initialize(errors)
-
7
@errors = errors
-
end
-
end
-
-
# Raised when a primary key is needed, but there is not one specified in the schema or model.
-
1
class UnknownPrimaryKey < ActiveRecordError
-
1
attr_reader :model
-
-
1
def initialize(model)
-
3
super("Unknown primary key for table #{model.table_name} in model #{model}.")
-
3
@model = model
-
end
-
-
end
-
-
# Raised when a relation cannot be mutated because it's already loaded.
-
#
-
# class Task < ActiveRecord::Base
-
# end
-
#
-
# relation = Task.all
-
# relation.loaded? # => true
-
#
-
# # Methods which try to mutate a loaded relation fail.
-
# relation.where!(title: 'TODO') # => ActiveRecord::ImmutableRelation
-
# relation.limit!(5) # => ActiveRecord::ImmutableRelation
-
1
class ImmutableRelation < ActiveRecordError
-
end
-
-
1
class TransactionIsolationError < ActiveRecordError
-
end
-
end
-
1
require 'active_support/lazy_load_hooks'
-
-
1
module ActiveRecord
-
1
module Explain
-
1
def self.extended(base)
-
1
base.mattr_accessor :auto_explain_threshold_in_seconds, instance_accessor: false
-
end
-
-
# If auto explain is enabled, this method triggers EXPLAIN logging for the
-
# queries triggered by the block if it takes more than the threshold as a
-
# whole. That is, the threshold is not checked against each individual
-
# query, but against the duration of the entire block. This approach is
-
# convenient for relations.
-
#
-
# The available_queries_for_explain thread variable collects the queries
-
# to be explained. If the value is nil, it means queries are not being
-
# currently collected. A false value indicates collecting is turned
-
# off. Otherwise it is an array of queries.
-
1
def logging_query_plan # :nodoc:
-
13944
return yield unless logger
-
-
13940
threshold = auto_explain_threshold_in_seconds
-
13940
current = Thread.current
-
13940
if threshold && current[:available_queries_for_explain].nil?
-
2
begin
-
2
queries = current[:available_queries_for_explain] = []
-
2
start = Time.now
-
2
result = yield
-
2
logger.warn(exec_explain(queries)) if Time.now - start > threshold
-
2
result
-
ensure
-
2
current[:available_queries_for_explain] = nil
-
end
-
else
-
13938
yield
-
end
-
end
-
-
# Relation#explain needs to be able to collect the queries regardless of
-
# whether auto explain is enabled. This method serves that purpose.
-
1
def collecting_queries_for_explain # :nodoc:
-
3
current = Thread.current
-
3
original, current[:available_queries_for_explain] = current[:available_queries_for_explain], []
-
3
return yield, current[:available_queries_for_explain]
-
ensure
-
# Note that the return value above does not depend on this assigment.
-
3
current[:available_queries_for_explain] = original
-
end
-
-
# Makes the adapter execute EXPLAIN for the tuples of queries and bindings.
-
# Returns a formatted string ready to be logged.
-
1
def exec_explain(queries) # :nodoc:
-
6
str = queries && queries.map do |sql, bind|
-
9
[].tap do |msg|
-
9
msg << "EXPLAIN for: #{sql}"
-
9
unless bind.empty?
-
4
bind_msg = bind.map {|col, val| [col.name, val]}.inspect
-
2
msg.last << " #{bind_msg}"
-
end
-
9
msg << connection.explain(sql, bind)
-
end.join("\n")
-
end.join("\n")
-
-
# Overriding inspect to be more human readable, specially in the console.
-
6
def str.inspect
-
self
-
end
-
6
str
-
end
-
-
# Silences automatic EXPLAIN logging for the duration of the block.
-
#
-
# This has high priority, no EXPLAINs will be run even if downwards
-
# the threshold is set to 0.
-
#
-
# As the name of the method suggests this only applies to automatic
-
# EXPLAINs, manual calls to <tt>ActiveRecord::Relation#explain</tt> run.
-
1
def silence_auto_explain
-
1
current = Thread.current
-
1
original, current[:available_queries_for_explain] = current[:available_queries_for_explain], false
-
1
yield
-
ensure
-
1
current[:available_queries_for_explain] = original
-
end
-
end
-
end
-
1
require 'active_support/notifications'
-
-
1
module ActiveRecord
-
1
class ExplainSubscriber # :nodoc:
-
1
def start(name, id, payload)
-
# unused
-
end
-
-
1
def finish(name, id, payload)
-
67861
if queries = Thread.current[:available_queries_for_explain]
-
19219
queries << payload.values_at(:sql, :binds) unless ignore_payload?(payload)
-
end
-
end
-
-
# SCHEMA queries cannot be EXPLAINed, also we do not want to run EXPLAIN on
-
# our own EXPLAINs now matter how loopingly beautiful that would be.
-
#
-
# On the other hand, we want to monitor the performance of our real database
-
# queries, not the performance of the access to the query cache.
-
1
IGNORED_PAYLOADS = %w(SCHEMA EXPLAIN CACHE)
-
1
EXPLAINED_SQLS = /\A\s*(select|update|delete|insert)/i
-
1
def ignore_payload?(payload)
-
19219
payload[:exception] || IGNORED_PAYLOADS.include?(payload[:name]) || payload[:sql] !~ EXPLAINED_SQLS
-
end
-
-
1
ActiveSupport::Notifications.subscribe("sql.active_record", new)
-
end
-
end
-
1
require 'erb'
-
1
require 'yaml'
-
-
1
module ActiveRecord
-
1
class FixtureSet
-
1
class File # :nodoc:
-
1
include Enumerable
-
-
##
-
# Open a fixture file named +file+. When called with a block, the block
-
# is called with the filehandle and the filehandle is automatically closed
-
# when the block finishes.
-
1
def self.open(file)
-
911
x = new file
-
911
block_given? ? yield(x) : x
-
end
-
-
1
def initialize(file)
-
911
@file = file
-
911
@rows = nil
-
end
-
-
1
def each(&block)
-
911
rows.each(&block)
-
end
-
-
1
RESCUE_ERRORS = [ ArgumentError, Psych::SyntaxError ] # :nodoc:
-
-
1
private
-
1
def rows
-
911
return @rows if @rows
-
-
911
begin
-
911
data = YAML.load(render(IO.read(@file)))
-
rescue *RESCUE_ERRORS => error
-
1
raise Fixture::FormatError, "a YAML error occurred parsing #{@file}. Please note that YAML must be consistently indented using spaces. Tabs are not allowed. Please have a look at http://www.yaml.org/faq.html\nThe exact error was:\n #{error.class}: #{error}", error.backtrace
-
end
-
909
@rows = data ? validate(data).to_a : []
-
end
-
-
1
def render(content)
-
910
ERB.new(content).result
-
end
-
-
# Validate our unmarshalled data.
-
1
def validate(data)
-
904
unless Hash === data || YAML::Omap === data
-
2
raise Fixture::FormatError, 'fixture is not a hash'
-
end
-
-
5228
raise Fixture::FormatError unless data.all? { |name, row| Hash === row }
-
901
data
-
end
-
end
-
end
-
end
-
1
require 'erb'
-
1
require 'yaml'
-
1
require 'zlib'
-
1
require 'active_support/dependencies'
-
1
require 'active_record/fixture_set/file'
-
1
require 'active_record/errors'
-
-
1
require 'active_support/deprecation' # temporary
-
-
1
module ActiveRecord
-
1
class FixtureClassNotFound < ActiveRecord::ActiveRecordError #:nodoc:
-
end
-
-
# \Fixtures are a way of organizing data that you want to test against; in short, sample data.
-
#
-
# They are stored in YAML files, one file per model, which are placed in the directory
-
# appointed by <tt>ActiveSupport::TestCase.fixture_path=(path)</tt> (this is automatically
-
# configured for Rails, so you can just put your files in <tt><your-rails-app>/test/fixtures/</tt>).
-
# The fixture file ends with the <tt>.yml</tt> file extension (Rails example:
-
# <tt><your-rails-app>/test/fixtures/web_sites.yml</tt>). The format of a fixture file looks
-
# like this:
-
#
-
# rubyonrails:
-
# id: 1
-
# name: Ruby on Rails
-
# url: http://www.rubyonrails.org
-
#
-
# google:
-
# id: 2
-
# name: Google
-
# url: http://www.google.com
-
#
-
# This fixture file includes two fixtures. Each YAML fixture (ie. record) is given a name and
-
# is followed by an indented list of key/value pairs in the "key: value" format. Records are
-
# separated by a blank line for your viewing pleasure.
-
#
-
# Note that fixtures are unordered. If you want ordered fixtures, use the omap YAML type.
-
# See http://yaml.org/type/omap.html
-
# for the specification. You will need ordered fixtures when you have foreign key constraints
-
# on keys in the same table. This is commonly needed for tree structures. Example:
-
#
-
# --- !omap
-
# - parent:
-
# id: 1
-
# parent_id: NULL
-
# title: Parent
-
# - child:
-
# id: 2
-
# parent_id: 1
-
# title: Child
-
#
-
# = Using Fixtures in Test Cases
-
#
-
# Since fixtures are a testing construct, we use them in our unit and functional tests. There
-
# are two ways to use the fixtures, but first let's take a look at a sample unit test:
-
#
-
# require 'test_helper'
-
#
-
# class WebSiteTest < ActiveSupport::TestCase
-
# test "web_site_count" do
-
# assert_equal 2, WebSite.count
-
# end
-
# end
-
#
-
# By default, <tt>test_helper.rb</tt> will load all of your fixtures into your test database,
-
# so this test will succeed.
-
#
-
# The testing environment will automatically load the all fixtures into the database before each
-
# test. To ensure consistent data, the environment deletes the fixtures before running the load.
-
#
-
# In addition to being available in the database, the fixture's data may also be accessed by
-
# using a special dynamic method, which has the same name as the model, and accepts the
-
# name of the fixture to instantiate:
-
#
-
# test "find" do
-
# assert_equal "Ruby on Rails", web_sites(:rubyonrails).name
-
# end
-
#
-
# Alternatively, you may enable auto-instantiation of the fixture data. For instance, take the
-
# following tests:
-
#
-
# test "find_alt_method_1" do
-
# assert_equal "Ruby on Rails", @web_sites['rubyonrails']['name']
-
# end
-
#
-
# test "find_alt_method_2" do
-
# assert_equal "Ruby on Rails", @rubyonrails.name
-
# end
-
#
-
# In order to use these methods to access fixtured data within your testcases, you must specify one of the
-
# following in your <tt>ActiveSupport::TestCase</tt>-derived class:
-
#
-
# - to fully enable instantiated fixtures (enable alternate methods #1 and #2 above)
-
# self.use_instantiated_fixtures = true
-
#
-
# - create only the hash for the fixtures, do not 'find' each instance (enable alternate method #1 only)
-
# self.use_instantiated_fixtures = :no_instances
-
#
-
# Using either of these alternate methods incurs a performance hit, as the fixtured data must be fully
-
# traversed in the database to create the fixture hash and/or instance variables. This is expensive for
-
# large sets of fixtured data.
-
#
-
# = Dynamic fixtures with ERB
-
#
-
# Some times you don't care about the content of the fixtures as much as you care about the volume.
-
# In these cases, you can mix ERB in with your YAML fixtures to create a bunch of fixtures for load
-
# testing, like:
-
#
-
# <% 1.upto(1000) do |i| %>
-
# fix_<%= i %>:
-
# id: <%= i %>
-
# name: guy_<%= 1 %>
-
# <% end %>
-
#
-
# This will create 1000 very simple fixtures.
-
#
-
# Using ERB, you can also inject dynamic values into your fixtures with inserts like
-
# <tt><%= Date.today.strftime("%Y-%m-%d") %></tt>.
-
# This is however a feature to be used with some caution. The point of fixtures are that they're
-
# stable units of predictable sample data. If you feel that you need to inject dynamic values, then
-
# perhaps you should reexamine whether your application is properly testable. Hence, dynamic values
-
# in fixtures are to be considered a code smell.
-
#
-
# = Transactional Fixtures
-
#
-
# Test cases can use begin+rollback to isolate their changes to the database instead of having to
-
# delete+insert for every test case.
-
#
-
# class FooTest < ActiveSupport::TestCase
-
# self.use_transactional_fixtures = true
-
#
-
# test "godzilla" do
-
# assert !Foo.all.empty?
-
# Foo.destroy_all
-
# assert Foo.all.empty?
-
# end
-
#
-
# test "godzilla aftermath" do
-
# assert !Foo.all.empty?
-
# end
-
# end
-
#
-
# If you preload your test database with all fixture data (probably in the rake task) and use
-
# transactional fixtures, then you may omit all fixtures declarations in your test cases since
-
# all the data's already there and every case rolls back its changes.
-
#
-
# In order to use instantiated fixtures with preloaded data, set +self.pre_loaded_fixtures+ to
-
# true. This will provide access to fixture data for every table that has been loaded through
-
# fixtures (depending on the value of +use_instantiated_fixtures+).
-
#
-
# When *not* to use transactional fixtures:
-
#
-
# 1. You're testing whether a transaction works correctly. Nested transactions don't commit until
-
# all parent transactions commit, particularly, the fixtures transaction which is begun in setup
-
# and rolled back in teardown. Thus, you won't be able to verify
-
# the results of your transaction until Active Record supports nested transactions or savepoints (in progress).
-
# 2. Your database does not support transactions. Every Active Record database supports transactions except MySQL MyISAM.
-
# Use InnoDB, MaxDB, or NDB instead.
-
#
-
# = Advanced Fixtures
-
#
-
# Fixtures that don't specify an ID get some extra features:
-
#
-
# * Stable, autogenerated IDs
-
# * Label references for associations (belongs_to, has_one, has_many)
-
# * HABTM associations as inline lists
-
# * Autofilled timestamp columns
-
# * Fixture label interpolation
-
# * Support for YAML defaults
-
#
-
# == Stable, Autogenerated IDs
-
#
-
# Here, have a monkey fixture:
-
#
-
# george:
-
# id: 1
-
# name: George the Monkey
-
#
-
# reginald:
-
# id: 2
-
# name: Reginald the Pirate
-
#
-
# Each of these fixtures has two unique identifiers: one for the database
-
# and one for the humans. Why don't we generate the primary key instead?
-
# Hashing each fixture's label yields a consistent ID:
-
#
-
# george: # generated id: 503576764
-
# name: George the Monkey
-
#
-
# reginald: # generated id: 324201669
-
# name: Reginald the Pirate
-
#
-
# Active Record looks at the fixture's model class, discovers the correct
-
# primary key, and generates it right before inserting the fixture
-
# into the database.
-
#
-
# The generated ID for a given label is constant, so we can discover
-
# any fixture's ID without loading anything, as long as we know the label.
-
#
-
# == Label references for associations (belongs_to, has_one, has_many)
-
#
-
# Specifying foreign keys in fixtures can be very fragile, not to
-
# mention difficult to read. Since Active Record can figure out the ID of
-
# any fixture from its label, you can specify FK's by label instead of ID.
-
#
-
# === belongs_to
-
#
-
# Let's break out some more monkeys and pirates.
-
#
-
# ### in pirates.yml
-
#
-
# reginald:
-
# id: 1
-
# name: Reginald the Pirate
-
# monkey_id: 1
-
#
-
# ### in monkeys.yml
-
#
-
# george:
-
# id: 1
-
# name: George the Monkey
-
# pirate_id: 1
-
#
-
# Add a few more monkeys and pirates and break this into multiple files,
-
# and it gets pretty hard to keep track of what's going on. Let's
-
# use labels instead of IDs:
-
#
-
# ### in pirates.yml
-
#
-
# reginald:
-
# name: Reginald the Pirate
-
# monkey: george
-
#
-
# ### in monkeys.yml
-
#
-
# george:
-
# name: George the Monkey
-
# pirate: reginald
-
#
-
# Pow! All is made clear. Active Record reflects on the fixture's model class,
-
# finds all the +belongs_to+ associations, and allows you to specify
-
# a target *label* for the *association* (monkey: george) rather than
-
# a target *id* for the *FK* (<tt>monkey_id: 1</tt>).
-
#
-
# ==== Polymorphic belongs_to
-
#
-
# Supporting polymorphic relationships is a little bit more complicated, since
-
# Active Record needs to know what type your association is pointing at. Something
-
# like this should look familiar:
-
#
-
# ### in fruit.rb
-
#
-
# belongs_to :eater, :polymorphic => true
-
#
-
# ### in fruits.yml
-
#
-
# apple:
-
# id: 1
-
# name: apple
-
# eater_id: 1
-
# eater_type: Monkey
-
#
-
# Can we do better? You bet!
-
#
-
# apple:
-
# eater: george (Monkey)
-
#
-
# Just provide the polymorphic target type and Active Record will take care of the rest.
-
#
-
# === has_and_belongs_to_many
-
#
-
# Time to give our monkey some fruit.
-
#
-
# ### in monkeys.yml
-
#
-
# george:
-
# id: 1
-
# name: George the Monkey
-
#
-
# ### in fruits.yml
-
#
-
# apple:
-
# id: 1
-
# name: apple
-
#
-
# orange:
-
# id: 2
-
# name: orange
-
#
-
# grape:
-
# id: 3
-
# name: grape
-
#
-
# ### in fruits_monkeys.yml
-
#
-
# apple_george:
-
# fruit_id: 1
-
# monkey_id: 1
-
#
-
# orange_george:
-
# fruit_id: 2
-
# monkey_id: 1
-
#
-
# grape_george:
-
# fruit_id: 3
-
# monkey_id: 1
-
#
-
# Let's make the HABTM fixture go away.
-
#
-
# ### in monkeys.yml
-
#
-
# george:
-
# id: 1
-
# name: George the Monkey
-
# fruits: apple, orange, grape
-
#
-
# ### in fruits.yml
-
#
-
# apple:
-
# name: apple
-
#
-
# orange:
-
# name: orange
-
#
-
# grape:
-
# name: grape
-
#
-
# Zap! No more fruits_monkeys.yml file. We've specified the list of fruits
-
# on George's fixture, but we could've just as easily specified a list
-
# of monkeys on each fruit. As with +belongs_to+, Active Record reflects on
-
# the fixture's model class and discovers the +has_and_belongs_to_many+
-
# associations.
-
#
-
# == Autofilled Timestamp Columns
-
#
-
# If your table/model specifies any of Active Record's
-
# standard timestamp columns (+created_at+, +created_on+, +updated_at+, +updated_on+),
-
# they will automatically be set to <tt>Time.now</tt>.
-
#
-
# If you've set specific values, they'll be left alone.
-
#
-
# == Fixture label interpolation
-
#
-
# The label of the current fixture is always available as a column value:
-
#
-
# geeksomnia:
-
# name: Geeksomnia's Account
-
# subdomain: $LABEL
-
#
-
# Also, sometimes (like when porting older join table fixtures) you'll need
-
# to be able to get a hold of the identifier for a given label. ERB
-
# to the rescue:
-
#
-
# george_reginald:
-
# monkey_id: <%= ActiveRecord::FixtureSet.identify(:reginald) %>
-
# pirate_id: <%= ActiveRecord::FixtureSet.identify(:george) %>
-
#
-
# == Support for YAML defaults
-
#
-
# You probably already know how to use YAML to set and reuse defaults in
-
# your <tt>database.yml</tt> file. You can use the same technique in your fixtures:
-
#
-
# DEFAULTS: &DEFAULTS
-
# created_on: <%= 3.weeks.ago.to_s(:db) %>
-
#
-
# first:
-
# name: Smurf
-
# *DEFAULTS
-
#
-
# second:
-
# name: Fraggle
-
# *DEFAULTS
-
#
-
# Any fixture labeled "DEFAULTS" is safely ignored.
-
1
class FixtureSet
-
#--
-
# An instance of FixtureSet is normally stored in a single YAML file and possibly in a folder with the same name.
-
#++
-
-
1
MAX_ID = 2 ** 30 - 1
-
-
345
@@all_cached_fixtures = Hash.new { |h,k| h[k] = {} }
-
-
1
def self.default_fixture_model_name(fixture_set_name) # :nodoc:
-
817
ActiveRecord::Base.pluralize_table_names ?
-
fixture_set_name.singularize.camelize :
-
fixture_set_name.camelize
-
end
-
-
1
def self.default_fixture_table_name(fixture_set_name) # :nodoc:
-
"#{ ActiveRecord::Base.table_name_prefix }"\
-
50
"#{ fixture_set_name.tr('/', '_') }"\
-
"#{ ActiveRecord::Base.table_name_suffix }".to_sym
-
end
-
-
1
def self.reset_cache
-
613
@@all_cached_fixtures.clear
-
end
-
-
1
def self.cache_for_connection(connection)
-
1887
@@all_cached_fixtures[connection]
-
end
-
-
1
def self.fixture_is_cached?(connection, table_name)
-
1054
cache_for_connection(connection)[table_name]
-
end
-
-
1
def self.cached_fixtures(connection, keys_to_fetch = nil)
-
583
if keys_to_fetch
-
583
cache_for_connection(connection).values_at(*keys_to_fetch)
-
else
-
cache_for_connection(connection).values
-
end
-
end
-
-
1
def self.cache_fixtures(connection, fixtures_map)
-
250
cache_for_connection(connection).update(fixtures_map)
-
end
-
-
1
def self.instantiate_fixtures(object, fixture_set, load_instances = true)
-
189
if load_instances
-
186
fixture_set.each do |fixture_name, fixture|
-
790
begin
-
790
object.instance_variable_set "@#{fixture_name}", fixture.find
-
rescue FixtureClassNotFound
-
46
nil
-
end
-
end
-
end
-
end
-
-
1
def self.instantiate_all_loaded_fixtures(object, load_instances = true)
-
all_loaded_fixtures.each_value do |fixture_set|
-
instantiate_fixtures(object, fixture_set, load_instances)
-
end
-
end
-
-
1
cattr_accessor :all_loaded_fixtures
-
1
self.all_loaded_fixtures = {}
-
-
1
def self.create_fixtures(fixtures_directory, fixture_set_names, class_names = {})
-
584
fixture_set_names = Array(fixture_set_names).map(&:to_s)
-
584
class_names = class_names.stringify_keys
-
-
# FIXME: Apparently JK uses this.
-
584
connection = block_given? ? yield : ActiveRecord::Base.connection
-
-
584
files_to_read = fixture_set_names.reject { |fs_name|
-
1051
fixture_is_cached?(connection, fs_name)
-
}
-
-
584
unless files_to_read.empty?
-
251
connection.disable_referential_integrity do
-
251
fixtures_map = {}
-
-
251
fixture_sets = files_to_read.map do |fs_name|
-
832
fixtures_map[fs_name] = new( # ActiveRecord::FixtureSet.new
-
connection,
-
fs_name,
-
class_names[fs_name] || default_fixture_model_name(fs_name),
-
::File.join(fixtures_directory, fs_name))
-
end
-
-
250
all_loaded_fixtures.update(fixtures_map)
-
-
250
connection.transaction(:requires_new => true) do
-
250
fixture_sets.each do |fs|
-
831
conn = fs.model_class.respond_to?(:connection) ? fs.model_class.connection : connection
-
831
table_rows = fs.table_rows
-
-
831
table_rows.keys.each do |table|
-
834
conn.delete "DELETE FROM #{conn.quote_table_name(table)}", 'Fixture Delete'
-
end
-
-
831
table_rows.each do |fixture_set_name, rows|
-
834
rows.each do |row|
-
4211
conn.insert_fixture(row, fixture_set_name)
-
end
-
end
-
end
-
-
# Cap primary key sequences to max(pk).
-
250
if connection.respond_to?(:reset_pk_sequence!)
-
250
fixture_sets.each do |fs|
-
831
connection.reset_pk_sequence!(fs.table_name)
-
end
-
end
-
end
-
-
250
cache_fixtures(connection, fixtures_map)
-
end
-
end
-
583
cached_fixtures(connection, fixture_set_names)
-
end
-
-
# Returns a consistent, platform-independent identifier for +label+.
-
# Identifiers are positive integers less than 2^32.
-
1
def self.identify(label)
-
235
Zlib.crc32(label.to_s) % MAX_ID
-
end
-
-
1
attr_reader :table_name, :name, :fixtures, :model_class
-
-
1
def initialize(connection, name, class_name, path)
-
837
@fixtures = {} # Ordered hash
-
837
@name = name
-
837
@path = path
-
-
837
if class_name.is_a?(Class) # TODO: Should be an AR::Base type class, or any?
-
13
@model_class = class_name
-
else
-
824
@model_class = class_name.constantize rescue nil
-
end
-
-
837
@connection = ( model_class.respond_to?(:connection) ?
-
model_class.connection : connection )
-
-
837
@table_name = ( model_class.respond_to?(:table_name) ?
-
model_class.table_name :
-
self.class.default_fixture_table_name(name) )
-
-
837
read_fixture_files
-
end
-
-
1
def [](x)
-
3236
fixtures[x]
-
end
-
-
1
def []=(k,v)
-
fixtures[k] = v
-
end
-
-
1
def each(&block)
-
199
fixtures.each(&block)
-
end
-
-
1
def size
-
fixtures.size
-
end
-
-
# Return a hash of rows to be inserted. The key is the table, the value is
-
# a list of rows to insert to that table.
-
1
def table_rows
-
831
now = ActiveRecord::Base.default_timezone == :utc ? Time.now.utc : Time.now
-
831
now = now.to_s(:db)
-
-
# allow a standard key to be used for doing defaults in YAML
-
831
fixtures.delete('DEFAULTS')
-
-
# track any join tables we need to insert later
-
834
rows = Hash.new { |h,table| h[table] = [] }
-
-
831
rows[table_name] = fixtures.map do |label, fixture|
-
4187
row = fixture.to_hash
-
-
4187
if model_class && model_class < ActiveRecord::Base
-
# fill in timestamp columns if they aren't specified and the model is set to record_timestamps
-
4048
if model_class.record_timestamps
-
4044
timestamp_column_names.each do |c_name|
-
3430
row[c_name] = now unless row.key?(c_name)
-
end
-
end
-
-
# interpolate the fixture label
-
4048
row.each do |key, value|
-
20608
row[key] = label if value == "$LABEL"
-
end
-
-
# generate a primary key if necessary
-
4048
if has_primary_key_column? && !row.include?(primary_key_name)
-
118
row[primary_key_name] = ActiveRecord::FixtureSet.identify(label)
-
end
-
-
# If STI is used, find the correct subclass for association reflection
-
4048
reflection_class =
-
if row.include?(inheritance_column_name)
-
1499
row[inheritance_column_name].constantize rescue model_class
-
else
-
2549
model_class
-
end
-
-
4048
reflection_class.reflect_on_all_associations.each do |association|
-
80741
case association.macro
-
when :belongs_to
-
# Do not replace association name with association foreign key if they are named the same
-
6537
fk_name = (association.options[:foreign_key] || "#{association.name}_id").to_s
-
-
6537
if association.name.to_s != fk_name && value = row.delete(association.name.to_s)
-
77
if association.options[:polymorphic] && value.sub!(/\s*\(([^\)]*)\)\s*$/, "")
-
# support polymorphic belongs_to as "label (Type)"
-
8
row[association.foreign_type] = $1
-
end
-
-
77
row[fk_name] = ActiveRecord::FixtureSet.identify(value)
-
end
-
when :has_and_belongs_to_many
-
8924
if (targets = row.delete(association.name.to_s))
-
12
targets = targets.is_a?(Array) ? targets : targets.split(/\s*,\s*/)
-
12
table_name = association.join_table
-
12
rows[table_name].concat targets.map { |target|
-
{ association.foreign_key => row[primary_key_name],
-
24
association.association_foreign_key => ActiveRecord::FixtureSet.identify(target) }
-
}
-
end
-
end
-
end
-
end
-
-
4187
row
-
end
-
831
rows
-
end
-
-
1
private
-
1
def primary_key_name
-
5747
@primary_key_name ||= model_class && model_class.primary_key
-
end
-
-
1
def has_primary_key_column?
-
@has_primary_key_column ||= primary_key_name &&
-
4828
model_class.columns.any? { |c| c.name == primary_key_name }
-
end
-
-
1
def timestamp_column_names
-
@timestamp_column_names ||=
-
4044
%w(created_at created_on updated_at updated_on) & column_names
-
end
-
-
1
def inheritance_column_name
-
5547
@inheritance_column_name ||= model_class && model_class.inheritance_column
-
end
-
-
1
def column_names
-
6492
@column_names ||= @connection.columns(@table_name).collect { |c| c.name }
-
end
-
-
1
def read_fixture_files
-
837
yaml_files = Dir["#{@path}/**/*.yml"].select { |f|
-
66
::File.file?(f)
-
} + [yaml_file_path]
-
-
837
yaml_files.each do |file|
-
903
FixtureSet::File.open(file) do |fh|
-
903
fh.each do |fixture_name, row|
-
4290
fixtures[fixture_name] = ActiveRecord::Fixture.new(row, model_class)
-
end
-
end
-
end
-
end
-
-
1
def yaml_file_path
-
837
"#{@path}.yml"
-
end
-
-
end
-
-
#--
-
# Deprecate 'Fixtures' in favor of 'FixtureSet'.
-
#++
-
# :nodoc:
-
1
Fixtures = ActiveSupport::Deprecation::DeprecatedConstantProxy.new('ActiveRecord::Fixtures', 'ActiveRecord::FixtureSet')
-
-
1
class Fixture #:nodoc:
-
1
include Enumerable
-
-
1
class FixtureError < StandardError #:nodoc:
-
end
-
-
1
class FormatError < FixtureError #:nodoc:
-
end
-
-
1
attr_reader :model_class, :fixture
-
-
1
def initialize(fixture, model_class)
-
4290
@fixture = fixture
-
4290
@model_class = model_class
-
end
-
-
1
def class_name
-
model_class.name if model_class
-
end
-
-
1
def each
-
266
fixture.each { |item| yield item }
-
end
-
-
1
def [](key)
-
118
fixture[key]
-
end
-
-
1
alias :to_hash :fixture
-
-
1
def find
-
2127
if model_class
-
2080
model_class.find(fixture[model_class.primary_key])
-
else
-
47
raise FixtureClassNotFound, "No class attached to find."
-
end
-
end
-
end
-
end
-
-
1
module ActiveRecord
-
1
module TestFixtures
-
1
extend ActiveSupport::Concern
-
-
1
included do
-
1
setup :setup_fixtures
-
1
teardown :teardown_fixtures
-
-
1
class_attribute :fixture_path
-
1
class_attribute :fixture_table_names
-
1
class_attribute :fixture_class_names
-
1
class_attribute :use_transactional_fixtures
-
1
class_attribute :use_instantiated_fixtures # true, false, or :no_instances
-
1
class_attribute :pre_loaded_fixtures
-
-
1
self.fixture_table_names = []
-
1
self.use_transactional_fixtures = true
-
1
self.use_instantiated_fixtures = false
-
1
self.pre_loaded_fixtures = false
-
-
1
self.fixture_class_names = Hash.new do |h, fixture_set_name|
-
h[fixture_set_name] = ActiveRecord::FixtureSet.default_fixture_model_name(fixture_set_name)
-
end
-
end
-
-
1
module ClassMethods
-
# Sets the model class for a fixture when the class name cannot be inferred from the fixture name.
-
#
-
# Examples:
-
#
-
# set_fixture_class :some_fixture => SomeModel,
-
# 'namespaced/fixture' => Another::Model
-
#
-
# The keys must be the fixture names, that coincide with the short paths to the fixture files.
-
#--
-
# It is also possible to pass the class name instead of the class:
-
# set_fixture_class 'some_fixture' => 'SomeModel'
-
# I think this option is redundant, i propose to deprecate it.
-
# Isn't it easier to always pass the class itself?
-
# (2011-12-20 alexeymuranov)
-
#++
-
1
def set_fixture_class(class_names = {})
-
7
self.fixture_class_names = self.fixture_class_names.merge(class_names.stringify_keys)
-
end
-
-
1
def fixtures(*fixture_set_names)
-
109
if fixture_set_names.first == :all
-
1
fixture_set_names = Dir["#{fixture_path}/**/*.yml"].map { |f|
-
3
File.basename f, '.yml'
-
}
-
else
-
603
fixture_set_names = fixture_set_names.flatten.map { |n| n.to_s }
-
end
-
-
109
self.fixture_table_names |= fixture_set_names
-
109
require_fixture_classes(fixture_set_names)
-
109
setup_fixture_accessors(fixture_set_names)
-
end
-
-
1
def try_to_load_dependency(file_name)
-
500
require_dependency file_name
-
rescue LoadError => e
-
# Let's hope the developer has included it himself
-
-
# Let's warn in case this is a subdependency, otherwise
-
# subdependency error messages are totally cryptic
-
499
if ActiveRecord::Base.logger
-
499
ActiveRecord::Base.logger.warn("Unable to load #{file_name}, underlying cause #{e.message} \n\n #{e.backtrace.join("\n")}")
-
end
-
end
-
-
1
def require_fixture_classes(fixture_set_names = nil)
-
109
if fixture_set_names
-
607
fixture_set_names = fixture_set_names.map { |n| n.to_s }
-
else
-
fixture_set_names = fixture_table_names
-
end
-
-
109
fixture_set_names.each do |file_name|
-
498
file_name = file_name.singularize if ActiveRecord::Base.pluralize_table_names
-
498
try_to_load_dependency(file_name)
-
end
-
end
-
-
1
def setup_fixture_accessors(fixture_set_names = nil)
-
110
fixture_set_names = Array(fixture_set_names || fixture_table_names)
-
110
methods = Module.new do
-
110
fixture_set_names.each do |fs_name|
-
499
fs_name = fs_name.to_s
-
499
accessor_name = fs_name.tr('/', '_').to_sym
-
-
499
define_method(accessor_name) do |*fixture_names|
-
1866
force_reload = fixture_names.pop if fixture_names.last == true || fixture_names.last == :reload
-
-
1866
@fixture_cache[fs_name] ||= {}
-
-
1866
instances = fixture_names.map do |f_name|
-
1894
f_name = f_name.to_s
-
1894
@fixture_cache[fs_name].delete(f_name) if force_reload
-
-
1894
if @loaded_fixtures[fs_name][f_name]
-
1892
@fixture_cache[fs_name][f_name] ||= @loaded_fixtures[fs_name][f_name].find
-
else
-
2
raise StandardError, "No fixture named '#{f_name}' found for fixture set '#{fs_name}'"
-
end
-
end
-
-
1863
instances.size == 1 ? instances.first : instances
-
end
-
499
private accessor_name
-
end
-
end
-
110
include methods
-
end
-
-
1
def uses_transaction(*methods)
-
1
@uses_transaction = [] unless defined?(@uses_transaction)
-
2
@uses_transaction.concat methods.map { |m| m.to_s }
-
end
-
-
1
def uses_transaction?(method)
-
10011
@uses_transaction = [] unless defined?(@uses_transaction)
-
10011
@uses_transaction.include?(method.to_s)
-
end
-
end
-
-
1
def run_in_transaction?
-
use_transactional_fixtures &&
-
10920
!self.class.uses_transaction?(method_name)
-
end
-
-
1
def setup_fixtures
-
3640
return if ActiveRecord::Base.configurations.blank?
-
-
3640
if pre_loaded_fixtures && !use_transactional_fixtures
-
raise RuntimeError, 'pre_loaded_fixtures requires use_transactional_fixtures'
-
end
-
-
3640
@fixture_cache = {}
-
3640
@fixture_connections = []
-
3640
@@already_loaded_fixtures ||= {}
-
-
# Load fixtures once and begin transaction.
-
3640
if run_in_transaction?
-
3336
if @@already_loaded_fixtures[self.class]
-
3109
@loaded_fixtures = @@already_loaded_fixtures[self.class]
-
else
-
227
@loaded_fixtures = load_fixtures
-
226
@@already_loaded_fixtures[self.class] = @loaded_fixtures
-
end
-
3335
@fixture_connections = enlist_fixture_connections
-
3335
@fixture_connections.each do |connection|
-
16389
connection.begin_transaction joinable: false
-
end
-
# Load fixtures for every test.
-
else
-
304
ActiveRecord::FixtureSet.reset_cache
-
304
@@already_loaded_fixtures[self.class] = nil
-
304
@loaded_fixtures = load_fixtures
-
end
-
-
# Instantiate fixtures for every test if requested.
-
3639
instantiate_fixtures if use_instantiated_fixtures
-
end
-
-
1
def teardown_fixtures
-
3640
return unless defined?(ActiveRecord) && !ActiveRecord::Base.configurations.blank?
-
-
3640
unless run_in_transaction?
-
304
ActiveRecord::FixtureSet.reset_cache
-
end
-
-
# Rollback changes if a transaction is active.
-
3640
if run_in_transaction?
-
3336
@fixture_connections.each do |connection|
-
16389
connection.rollback_transaction if connection.transaction_open?
-
end
-
3336
@fixture_connections.clear
-
end
-
3640
ActiveRecord::Base.clear_active_connections!
-
end
-
-
1
def enlist_fixture_connections
-
3335
ActiveRecord::Base.connection_handler.connection_pool_list.map(&:connection)
-
end
-
-
1
private
-
1
def load_fixtures
-
530
fixtures = ActiveRecord::FixtureSet.create_fixtures(fixture_path, fixture_table_names, fixture_class_names)
-
1516
Hash[fixtures.map { |f| [f.name, f] }]
-
end
-
-
# for pre_loaded_fixtures, only require the classes once. huge speed improvement
-
1
@@required_fixture_classes = false
-
-
1
def instantiate_fixtures
-
26
if pre_loaded_fixtures
-
raise RuntimeError, 'Load fixtures before instantiating them.' if ActiveRecord::FixtureSet.all_loaded_fixtures.empty?
-
unless @@required_fixture_classes
-
self.class.require_fixture_classes ActiveRecord::FixtureSet.all_loaded_fixtures.keys
-
@@required_fixture_classes = true
-
end
-
ActiveRecord::FixtureSet.instantiate_all_loaded_fixtures(self, load_instances?)
-
else
-
26
raise RuntimeError, 'Load fixtures before instantiating them.' if @loaded_fixtures.nil?
-
26
@loaded_fixtures.each_value do |fixture_set|
-
189
ActiveRecord::FixtureSet.instantiate_fixtures(self, fixture_set, load_instances?)
-
end
-
end
-
end
-
-
1
def load_instances?
-
189
use_instantiated_fixtures != :no_instances
-
end
-
end
-
end
-
1
module ActiveRecord
-
1
module Inheritance
-
1
extend ActiveSupport::Concern
-
-
1
included do
-
# Determine whether to store the full constant name including namespace when using STI
-
2
class_attribute :store_full_sti_class, instance_writer: false
-
2
self.store_full_sti_class = true
-
end
-
-
1
module ClassMethods
-
# True if this isn't a concrete subclass needing a STI type condition.
-
1
def descends_from_active_record?
-
372
if self == Base
-
1
false
-
371
elsif superclass.abstract_class?
-
13
superclass.descends_from_active_record?
-
else
-
358
superclass == Base || !columns_hash.include?(inheritance_column)
-
end
-
end
-
-
1
def finder_needs_type_condition? #:nodoc:
-
# This is like this because benchmarking justifies the strange :false stuff
-
25417
:true == (@finder_needs_type_condition ||= descends_from_active_record? ? :false : :true)
-
end
-
-
1
def symbolized_base_class
-
@symbolized_base_class ||= base_class.to_s.to_sym
-
end
-
-
1
def symbolized_sti_name
-
@symbolized_sti_name ||= sti_name.present? ? sti_name.to_sym : symbolized_base_class
-
end
-
-
# Returns the class descending directly from ActiveRecord::Base, or
-
# an abstract class, if any, in the inheritance hierarchy.
-
#
-
# If A extends AR::Base, A.base_class will return A. If B descends from A
-
# through some arbitrarily deep hierarchy, B.base_class will return A.
-
#
-
# If B < A and C < B and if A is an abstract_class then both B.base_class
-
# and C.base_class would return B as the answer since A is an abstract_class.
-
1
def base_class
-
3619
unless self < Base
-
1
raise ActiveRecordError, "#{name} doesn't belong in a hierarchy descending from ActiveRecord"
-
end
-
-
3618
if superclass == Base || superclass.abstract_class?
-
2879
self
-
else
-
739
superclass.base_class
-
end
-
end
-
-
# Set this to true if this is an abstract class (see <tt>abstract_class?</tt>).
-
# If you are using inheritance with ActiveRecord and don't want child classes
-
# to utilize the implied STI table name of the parent class, this will need to be true.
-
# For example, given the following:
-
#
-
# class SuperClass < ActiveRecord::Base
-
# self.abstract_class = true
-
# end
-
# class Child < SuperClass
-
# self.table_name = 'the_table_i_really_want'
-
# end
-
#
-
#
-
# <tt>self.abstract_class = true</tt> is required to make <tt>Child<.find,.create, or any Arel method></tt> use <tt>the_table_i_really_want</tt> instead of a table called <tt>super_classes</tt>
-
#
-
1
attr_accessor :abstract_class
-
-
# Returns whether this class is an abstract class or not.
-
1
def abstract_class?
-
2351
defined?(@abstract_class) && @abstract_class == true
-
end
-
-
1
def sti_name
-
11151
store_full_sti_class ? name : name.demodulize
-
end
-
-
# Finder methods must instantiate through this method to work with the
-
# single-table inheritance model that makes it possible to create
-
# objects of different types from the same table.
-
1
def instantiate(record, column_types = {})
-
10718
sti_class = find_sti_class(record[inheritance_column])
-
10716
column_types = sti_class.decorate_columns(column_types)
-
10716
sti_class.allocate.init_with('attributes' => record, 'column_types' => column_types)
-
end
-
-
1
protected
-
-
# Returns the class type of the record using the current module as a prefix. So descendants of
-
# MyApp::Business::Account would appear as MyApp::Business::AccountSubclass.
-
1
def compute_type(type_name)
-
490
if type_name.match(/^::/)
-
# If the type is prefixed with a scope operator then we assume that
-
# the type_name is an absolute reference.
-
ActiveSupport::Dependencies.constantize(type_name)
-
else
-
# Build a list of candidates to search for
-
490
candidates = []
-
1053
name.scan(/::|$/) { candidates.unshift "#{$`}::#{type_name}" }
-
490
candidates << type_name
-
-
490
candidates.each do |candidate|
-
997
begin
-
997
constant = ActiveSupport::Dependencies.constantize(candidate)
-
486
return constant if candidate == constant.to_s
-
rescue NameError => e
-
# We don't want to swallow NoMethodError < NameError errors
-
510
raise e unless e.instance_of?(NameError)
-
end
-
end
-
-
2
raise NameError, "uninitialized constant #{candidates.first}"
-
end
-
end
-
-
1
private
-
-
1
def find_sti_class(type_name)
-
10718
if type_name.blank? || !columns_hash.include?(inheritance_column)
-
6291
self
-
else
-
4427
begin
-
4427
if store_full_sti_class
-
4408
ActiveSupport::Dependencies.constantize(type_name)
-
else
-
19
compute_type(type_name)
-
end
-
2
rescue NameError
-
2
raise SubclassNotFound,
-
"The single-table inheritance mechanism failed to locate the subclass: '#{type_name}'. " +
-
"This error is raised because the column '#{inheritance_column}' is reserved for storing the class in case of inheritance. " +
-
"Please rename this column if you didn't intend it to be used for storing the inheritance class " +
-
"or overwrite #{name}.inheritance_column to use another column for that information."
-
end
-
end
-
end
-
-
1
def type_condition(table = arel_table)
-
2727
sti_column = table[inheritance_column.to_sym]
-
10880
sti_names = ([self] + descendants).map { |model| model.sti_name }
-
-
2727
sti_column.in(sti_names)
-
end
-
end
-
-
1
private
-
-
# Sets the attribute used for single table inheritance to this class name if this is not the
-
# ActiveRecord::Base descendant.
-
# Considering the hierarchy Reply < Message < ActiveRecord::Base, this makes it possible to
-
# do Reply.new without having to set <tt>Reply[Reply.inheritance_column] = "Reply"</tt> yourself.
-
# No such attribute would be set for objects of the Message class in that example.
-
1
def ensure_proper_type
-
2991
klass = self.class
-
2991
if klass.finder_needs_type_condition?
-
284
write_attribute(klass.inheritance_column, klass.sti_name)
-
end
-
end
-
end
-
end
-
1
module ActiveRecord
-
1
module Integration
-
# Returns a String, which Action Pack uses for constructing an URL to this
-
# object. The default implementation returns this record's id as a String,
-
# or nil if this record's unsaved.
-
#
-
# For example, suppose that you have a User model, and that you have a
-
# <tt>resources :users</tt> route. Normally, +user_path+ will
-
# construct a path with the user object's 'id' in it:
-
#
-
# user = User.find_by_name('Phusion')
-
# user_path(user) # => "/users/1"
-
#
-
# You can override +to_param+ in your model to make +user_path+ construct
-
# a path using the user's name instead of the user's id:
-
#
-
# class User < ActiveRecord::Base
-
# def to_param # overridden
-
# name
-
# end
-
# end
-
#
-
# user = User.find_by_name('Phusion')
-
# user_path(user) # => "/users/Phusion"
-
1
def to_param
-
# We can't use alias_method here, because method 'id' optimizes itself on the fly.
-
3
id && id.to_s # Be sure to stringify the id for routes
-
end
-
-
# Returns a cache key that can be used to identify this record.
-
#
-
# ==== Examples
-
#
-
# Product.new.cache_key # => "products/new"
-
# Product.find(5).cache_key # => "products/5" (updated_at not available)
-
# Person.find(5).cache_key # => "people/5-20071224150000" (updated_at available)
-
1
def cache_key
-
case
-
when new_record?
-
"#{self.class.model_name.cache_key}/new"
-
when timestamp = self[:updated_at]
-
3
timestamp = timestamp.utc.to_s(:nsec)
-
3
"#{self.class.model_name.cache_key}/#{id}-#{timestamp}"
-
else
-
1
"#{self.class.model_name.cache_key}/#{id}"
-
4
end
-
end
-
end
-
end
-
1
module ActiveRecord
-
1
module Locking
-
# == What is Optimistic Locking
-
#
-
# Optimistic locking allows multiple users to access the same record for edits, and assumes a minimum of
-
# conflicts with the data. It does this by checking whether another process has made changes to a record since
-
# it was opened, an <tt>ActiveRecord::StaleObjectError</tt> exception is thrown if that has occurred
-
# and the update is ignored.
-
#
-
# Check out <tt>ActiveRecord::Locking::Pessimistic</tt> for an alternative.
-
#
-
# == Usage
-
#
-
# Active Records support optimistic locking if the field +lock_version+ is present. Each update to the
-
# record increments the +lock_version+ column and the locking facilities ensure that records instantiated twice
-
# will let the last one saved raise a +StaleObjectError+ if the first was also updated. Example:
-
#
-
# p1 = Person.find(1)
-
# p2 = Person.find(1)
-
#
-
# p1.first_name = "Michael"
-
# p1.save
-
#
-
# p2.first_name = "should fail"
-
# p2.save # Raises a ActiveRecord::StaleObjectError
-
#
-
# Optimistic locking will also check for stale data when objects are destroyed. Example:
-
#
-
# p1 = Person.find(1)
-
# p2 = Person.find(1)
-
#
-
# p1.first_name = "Michael"
-
# p1.save
-
#
-
# p2.destroy # Raises a ActiveRecord::StaleObjectError
-
#
-
# You're then responsible for dealing with the conflict by rescuing the exception and either rolling back, merging,
-
# or otherwise apply the business logic needed to resolve the conflict.
-
#
-
# This locking mechanism will function inside a single Ruby process. To make it work across all
-
# web requests, the recommended approach is to add +lock_version+ as a hidden field to your form.
-
#
-
# This behavior can be turned off by setting <tt>ActiveRecord::Base.lock_optimistically = false</tt>.
-
# To override the name of the +lock_version+ column, set the <tt>locking_column</tt> class attribute:
-
#
-
# class Person < ActiveRecord::Base
-
# self.locking_column = :lock_person
-
# end
-
#
-
1
module Optimistic
-
1
extend ActiveSupport::Concern
-
-
1
included do
-
1
class_attribute :lock_optimistically, instance_writer: false
-
1
self.lock_optimistically = true
-
end
-
-
1
def locking_enabled? #:nodoc:
-
1095
self.class.locking_enabled?
-
end
-
-
1
private
-
1
def increment_lock
-
24
lock_col = self.class.locking_column
-
24
previous_lock_value = send(lock_col).to_i
-
24
send(lock_col + '=', previous_lock_value + 1)
-
end
-
-
1
def update(attribute_names = @attributes.keys) #:nodoc:
-
612
return super unless locking_enabled?
-
26
return 0 if attribute_names.empty?
-
-
23
lock_col = self.class.locking_column
-
23
previous_lock_value = send(lock_col).to_i
-
23
increment_lock
-
-
23
attribute_names += [lock_col]
-
23
attribute_names.uniq!
-
-
23
begin
-
23
relation = self.class.unscoped
-
-
23
stmt = relation.where(
-
relation.table[self.class.primary_key].eq(id).and(
-
relation.table[lock_col].eq(self.class.quote_value(previous_lock_value))
-
)
-
).arel.compile_update(arel_attributes_with_values_for_update(attribute_names))
-
-
23
affected_rows = connection.update stmt
-
-
23
unless affected_rows == 1
-
7
raise ActiveRecord::StaleObjectError.new(self, "update")
-
end
-
-
16
affected_rows
-
-
# If something went wrong, revert the version.
-
7
rescue Exception
-
7
send(lock_col + '=', previous_lock_value)
-
7
raise
-
end
-
end
-
-
1
def destroy_row
-
228
affected_rows = super
-
-
228
if locking_enabled? && affected_rows != 1
-
2
raise ActiveRecord::StaleObjectError.new(self, "destroy")
-
end
-
-
226
affected_rows
-
end
-
-
1
def relation_for_destroy
-
228
relation = super
-
-
228
if locking_enabled?
-
18
column_name = self.class.locking_column
-
18
column = self.class.columns_hash[column_name]
-
18
substitute = connection.substitute_at(column, relation.bind_values.length)
-
-
18
relation = relation.where(self.class.arel_table[column_name].eq(substitute))
-
18
relation.bind_values << [column, self[column_name].to_i]
-
end
-
-
228
relation
-
end
-
-
1
module ClassMethods
-
1
DEFAULT_LOCKING_COLUMN = 'lock_version'
-
-
# Returns true if the +lock_optimistically+ flag is set to true
-
# (which it is, by default) and the table includes the
-
# +locking_column+ column (defaults to +lock_version+).
-
1
def locking_enabled?
-
1239
lock_optimistically && columns_hash[locking_column]
-
end
-
-
# Set the column to use for optimistic locking. Defaults to +lock_version+.
-
1
def locking_column=(value)
-
260
@locking_column = value.to_s
-
end
-
-
# The version column used for optimistic locking. Defaults to +lock_version+.
-
1
def locking_column
-
1584
reset_locking_column unless defined?(@locking_column)
-
1584
@locking_column
-
end
-
-
# Quote the column name used for optimistic locking.
-
1
def quoted_locking_column
-
connection.quote_column_name(locking_column)
-
end
-
-
# Reset the column used for optimistic locking back to the +lock_version+ default.
-
1
def reset_locking_column
-
258
self.locking_column = DEFAULT_LOCKING_COLUMN
-
end
-
-
# Make sure the lock version column gets updated when counters are
-
# updated.
-
1
def update_counters(id, counters)
-
144
counters = counters.merge(locking_column => 1) if locking_enabled?
-
144
super
-
end
-
-
1
def column_defaults
-
@column_defaults ||= begin
-
248
defaults = super
-
-
247
if defaults.key?(locking_column) && lock_optimistically
-
11
defaults[locking_column] ||= 0
-
end
-
-
247
defaults
-
2992
end
-
end
-
end
-
end
-
end
-
end
-
1
module ActiveRecord
-
1
module Locking
-
# Locking::Pessimistic provides support for row-level locking using
-
# SELECT ... FOR UPDATE and other lock types.
-
#
-
# Pass <tt>:lock => true</tt> to <tt>ActiveRecord::Base.find</tt> to obtain an exclusive
-
# lock on the selected rows:
-
# # select * from accounts where id=1 for update
-
# Account.find(1, :lock => true)
-
#
-
# Pass <tt>:lock => 'some locking clause'</tt> to give a database-specific locking clause
-
# of your own such as 'LOCK IN SHARE MODE' or 'FOR UPDATE NOWAIT'. Example:
-
#
-
# Account.transaction do
-
# # select * from accounts where name = 'shugo' limit 1 for update
-
# shugo = Account.where("name = 'shugo'").lock(true).first
-
# yuko = Account.where("name = 'yuko'").lock(true).first
-
# shugo.balance -= 100
-
# shugo.save!
-
# yuko.balance += 100
-
# yuko.save!
-
# end
-
#
-
# You can also use <tt>ActiveRecord::Base#lock!</tt> method to lock one record by id.
-
# This may be better if you don't need to lock every row. Example:
-
#
-
# Account.transaction do
-
# # select * from accounts where ...
-
# accounts = Account.where(...).all
-
# account1 = accounts.detect { |account| ... }
-
# account2 = accounts.detect { |account| ... }
-
# # select * from accounts where id=? for update
-
# account1.lock!
-
# account2.lock!
-
# account1.balance -= 100
-
# account1.save!
-
# account2.balance += 100
-
# account2.save!
-
# end
-
#
-
# You can start a transaction and acquire the lock in one go by calling
-
# <tt>with_lock</tt> with a block. The block is called from within
-
# a transaction, the object is already locked. Example:
-
#
-
# account = Account.first
-
# account.with_lock do
-
# # This block is called within a transaction,
-
# # account is already locked.
-
# account.balance -= 100
-
# account.save!
-
# end
-
#
-
# Database-specific information on row locking:
-
# MySQL: http://dev.mysql.com/doc/refman/5.1/en/innodb-locking-reads.html
-
# PostgreSQL: http://www.postgresql.org/docs/current/interactive/sql-select.html#SQL-FOR-UPDATE-SHARE
-
1
module Pessimistic
-
# Obtain a row lock on this record. Reloads the record to obtain the requested
-
# lock. Pass an SQL locking clause to append the end of the SELECT statement
-
# or pass true for "FOR UPDATE" (the default, an exclusive row lock). Returns
-
# the locked record.
-
1
def lock!(lock = true)
-
5
reload(:lock => lock) if persisted?
-
5
self
-
end
-
-
# Wraps the passed block in a transaction, locking the object
-
# before yielding. You pass can the SQL locking clause
-
# as argument (see <tt>lock!</tt>).
-
1
def with_lock(lock = true)
-
2
transaction do
-
2
lock!(lock)
-
2
yield
-
end
-
end
-
end
-
end
-
end
-
1
module ActiveRecord
-
1
class LogSubscriber < ActiveSupport::LogSubscriber
-
1
IGNORE_PAYLOAD_NAMES = ["SCHEMA", "EXPLAIN"]
-
-
1
def self.runtime=(value)
-
67844
Thread.current[:active_record_sql_runtime] = value
-
end
-
-
1
def self.runtime
-
67845
Thread.current[:active_record_sql_runtime] ||= 0
-
end
-
-
1
def self.reset_runtime
-
rt, self.runtime = runtime, 0
-
rt
-
end
-
-
1
def initialize
-
10
super
-
10
@odd_or_even = false
-
end
-
-
1
def sql(event)
-
67844
self.class.runtime += event.duration
-
67844
return unless logger.debug?
-
-
67838
payload = event.payload
-
-
67838
return if IGNORE_PAYLOAD_NAMES.include?(payload[:name])
-
-
46176
name = "#{payload[:name]} (#{event.duration.round(1)}ms)"
-
46176
sql = payload[:sql].squeeze(' ')
-
46176
binds = nil
-
-
46176
unless (payload[:binds] || []).empty?
-
7844
binds = " " + payload[:binds].map { |col,v|
-
11687
[col.name, v]
-
}.inspect
-
end
-
-
46169
if odd?
-
23086
name = color(name, CYAN, true)
-
23086
sql = color(sql, nil, true)
-
else
-
23083
name = color(name, MAGENTA, true)
-
end
-
-
46169
debug " #{name} #{sql}#{binds}"
-
end
-
-
1
def identity(event)
-
return unless logger.debug?
-
-
name = color(event.payload[:name], odd? ? CYAN : MAGENTA, true)
-
line = odd? ? color(event.payload[:line], nil, true) : event.payload[:line]
-
-
debug " #{name} #{line}"
-
end
-
-
1
def odd?
-
46169
@odd_or_even = !@odd_or_even
-
end
-
-
1
def logger
-
295895
ActiveRecord::Base.logger
-
end
-
end
-
end
-
-
1
ActiveRecord::LogSubscriber.attach_to :active_record
-
1
require "active_support/core_ext/class/attribute_accessors"
-
1
require 'set'
-
-
1
module ActiveRecord
-
# Exception that can be raised to stop migrations from going backwards.
-
1
class IrreversibleMigration < ActiveRecordError
-
end
-
-
1
class DuplicateMigrationVersionError < ActiveRecordError#:nodoc:
-
1
def initialize(version)
-
1
super("Multiple migrations have the version number #{version}")
-
end
-
end
-
-
1
class DuplicateMigrationNameError < ActiveRecordError#:nodoc:
-
1
def initialize(name)
-
1
super("Multiple migrations have the name #{name}")
-
end
-
end
-
-
1
class UnknownMigrationVersionError < ActiveRecordError #:nodoc:
-
1
def initialize(version)
-
1
super("No migration with version number #{version}")
-
end
-
end
-
-
1
class IllegalMigrationNameError < ActiveRecordError#:nodoc:
-
1
def initialize(name)
-
super("Illegal name for migration file: #{name}\n\t(only lower case letters, numbers, and '_' allowed)")
-
end
-
end
-
-
1
class PendingMigrationError < ActiveRecordError#:nodoc:
-
1
def initialize
-
super("Migrations are pending; run 'rake db:migrate RAILS_ENV=#{ENV['RAILS_ENV']}' to resolve this issue.")
-
end
-
end
-
-
# = Active Record Migrations
-
#
-
# Migrations can manage the evolution of a schema used by several physical
-
# databases. It's a solution to the common problem of adding a field to make
-
# a new feature work in your local database, but being unsure of how to
-
# push that change to other developers and to the production server. With
-
# migrations, you can describe the transformations in self-contained classes
-
# that can be checked into version control systems and executed against
-
# another database that might be one, two, or five versions behind.
-
#
-
# Example of a simple migration:
-
#
-
# class AddSsl < ActiveRecord::Migration
-
# def up
-
# add_column :accounts, :ssl_enabled, :boolean, default: true
-
# end
-
#
-
# def down
-
# remove_column :accounts, :ssl_enabled
-
# end
-
# end
-
#
-
# This migration will add a boolean flag to the accounts table and remove it
-
# if you're backing out of the migration. It shows how all migrations have
-
# two methods +up+ and +down+ that describes the transformations
-
# required to implement or remove the migration. These methods can consist
-
# of both the migration specific methods like +add_column+ and +remove_column+,
-
# but may also contain regular Ruby code for generating data needed for the
-
# transformations.
-
#
-
# Example of a more complex migration that also needs to initialize data:
-
#
-
# class AddSystemSettings < ActiveRecord::Migration
-
# def up
-
# create_table :system_settings do |t|
-
# t.string :name
-
# t.string :label
-
# t.text :value
-
# t.string :type
-
# t.integer :position
-
# end
-
#
-
# SystemSetting.create name: 'notice',
-
# label: 'Use notice?',
-
# value: 1
-
# end
-
#
-
# def down
-
# drop_table :system_settings
-
# end
-
# end
-
#
-
# This migration first adds the +system_settings+ table, then creates the very
-
# first row in it using the Active Record model that relies on the table. It
-
# also uses the more advanced +create_table+ syntax where you can specify a
-
# complete table schema in one block call.
-
#
-
# == Available transformations
-
#
-
# * <tt>create_table(name, options)</tt>: Creates a table called +name+ and
-
# makes the table object available to a block that can then add columns to it,
-
# following the same format as +add_column+. See example above. The options hash
-
# is for fragments like "DEFAULT CHARSET=UTF-8" that are appended to the create
-
# table definition.
-
# * <tt>drop_table(name)</tt>: Drops the table called +name+.
-
# * <tt>change_table(name, options)</tt>: Allows to make column alterations to
-
# the table called +name+. It makes the table object availabe to a block that
-
# can then add/remove columns, indexes or foreign keys to it.
-
# * <tt>rename_table(old_name, new_name)</tt>: Renames the table called +old_name+
-
# to +new_name+.
-
# * <tt>add_column(table_name, column_name, type, options)</tt>: Adds a new column
-
# to the table called +table_name+
-
# named +column_name+ specified to be one of the following types:
-
# <tt>:string</tt>, <tt>:text</tt>, <tt>:integer</tt>, <tt>:float</tt>,
-
# <tt>:decimal</tt>, <tt>:datetime</tt>, <tt>:timestamp</tt>, <tt>:time</tt>,
-
# <tt>:date</tt>, <tt>:binary</tt>, <tt>:boolean</tt>. A default value can be
-
# specified by passing an +options+ hash like <tt>{ default: 11 }</tt>.
-
# Other options include <tt>:limit</tt> and <tt>:null</tt> (e.g.
-
# <tt>{ limit: 50, null: false }</tt>) -- see
-
# ActiveRecord::ConnectionAdapters::TableDefinition#column for details.
-
# * <tt>rename_column(table_name, column_name, new_column_name)</tt>: Renames
-
# a column but keeps the type and content.
-
# * <tt>change_column(table_name, column_name, type, options)</tt>: Changes
-
# the column to a different type using the same parameters as add_column.
-
# * <tt>remove_column(table_name, column_names)</tt>: Removes the column listed in
-
# +column_names+ from the table called +table_name+.
-
# * <tt>add_index(table_name, column_names, options)</tt>: Adds a new index
-
# with the name of the column. Other options include
-
# <tt>:name</tt>, <tt>:unique</tt> (e.g.
-
# <tt>{ name: 'users_name_index', unique: true }</tt>) and <tt>:order</tt>
-
# (e.g. <tt>{ order: { name: :desc } }</tt>).
-
# * <tt>remove_index(table_name, column: column_name)</tt>: Removes the index
-
# specified by +column_name+.
-
# * <tt>remove_index(table_name, name: index_name)</tt>: Removes the index
-
# specified by +index_name+.
-
#
-
# == Irreversible transformations
-
#
-
# Some transformations are destructive in a manner that cannot be reversed.
-
# Migrations of that kind should raise an <tt>ActiveRecord::IrreversibleMigration</tt>
-
# exception in their +down+ method.
-
#
-
# == Running migrations from within Rails
-
#
-
# The Rails package has several tools to help create and apply migrations.
-
#
-
# To generate a new migration, you can use
-
# rails generate migration MyNewMigration
-
#
-
# where MyNewMigration is the name of your migration. The generator will
-
# create an empty migration file <tt>timestamp_my_new_migration.rb</tt>
-
# in the <tt>db/migrate/</tt> directory where <tt>timestamp</tt> is the
-
# UTC formatted date and time that the migration was generated.
-
#
-
# You may then edit the <tt>up</tt> and <tt>down</tt> methods of
-
# MyNewMigration.
-
#
-
# There is a special syntactic shortcut to generate migrations that add fields to a table.
-
#
-
# rails generate migration add_fieldname_to_tablename fieldname:string
-
#
-
# This will generate the file <tt>timestamp_add_fieldname_to_tablename</tt>, which will look like this:
-
# class AddFieldnameToTablename < ActiveRecord::Migration
-
# def up
-
# add_column :tablenames, :fieldname, :string
-
# end
-
#
-
# def down
-
# remove_column :tablenames, :fieldname
-
# end
-
# end
-
#
-
# To run migrations against the currently configured database, use
-
# <tt>rake db:migrate</tt>. This will update the database by running all of the
-
# pending migrations, creating the <tt>schema_migrations</tt> table
-
# (see "About the schema_migrations table" section below) if missing. It will also
-
# invoke the db:schema:dump task, which will update your db/schema.rb file
-
# to match the structure of your database.
-
#
-
# To roll the database back to a previous migration version, use
-
# <tt>rake db:migrate VERSION=X</tt> where <tt>X</tt> is the version to which
-
# you wish to downgrade. If any of the migrations throw an
-
# <tt>ActiveRecord::IrreversibleMigration</tt> exception, that step will fail and you'll
-
# have some manual work to do.
-
#
-
# == Database support
-
#
-
# Migrations are currently supported in MySQL, PostgreSQL, SQLite,
-
# SQL Server, Sybase, and Oracle (all supported databases except DB2).
-
#
-
# == More examples
-
#
-
# Not all migrations change the schema. Some just fix the data:
-
#
-
# class RemoveEmptyTags < ActiveRecord::Migration
-
# def up
-
# Tag.all.each { |tag| tag.destroy if tag.pages.empty? }
-
# end
-
#
-
# def down
-
# # not much we can do to restore deleted data
-
# raise ActiveRecord::IrreversibleMigration, "Can't recover the deleted tags"
-
# end
-
# end
-
#
-
# Others remove columns when they migrate up instead of down:
-
#
-
# class RemoveUnnecessaryItemAttributes < ActiveRecord::Migration
-
# def up
-
# remove_column :items, :incomplete_items_count
-
# remove_column :items, :completed_items_count
-
# end
-
#
-
# def down
-
# add_column :items, :incomplete_items_count
-
# add_column :items, :completed_items_count
-
# end
-
# end
-
#
-
# And sometimes you need to do something in SQL not abstracted directly by migrations:
-
#
-
# class MakeJoinUnique < ActiveRecord::Migration
-
# def up
-
# execute "ALTER TABLE `pages_linked_pages` ADD UNIQUE `page_id_linked_page_id` (`page_id`,`linked_page_id`)"
-
# end
-
#
-
# def down
-
# execute "ALTER TABLE `pages_linked_pages` DROP INDEX `page_id_linked_page_id`"
-
# end
-
# end
-
#
-
# == Using a model after changing its table
-
#
-
# Sometimes you'll want to add a column in a migration and populate it
-
# immediately after. In that case, you'll need to make a call to
-
# <tt>Base#reset_column_information</tt> in order to ensure that the model has the
-
# latest column data from after the new column was added. Example:
-
#
-
# class AddPeopleSalary < ActiveRecord::Migration
-
# def up
-
# add_column :people, :salary, :integer
-
# Person.reset_column_information
-
# Person.all.each do |p|
-
# p.update_attribute :salary, SalaryCalculator.compute(p)
-
# end
-
# end
-
# end
-
#
-
# == Controlling verbosity
-
#
-
# By default, migrations will describe the actions they are taking, writing
-
# them to the console as they happen, along with benchmarks describing how
-
# long each step took.
-
#
-
# You can quiet them down by setting ActiveRecord::Migration.verbose = false.
-
#
-
# You can also insert your own messages and benchmarks by using the +say_with_time+
-
# method:
-
#
-
# def up
-
# ...
-
# say_with_time "Updating salaries..." do
-
# Person.all.each do |p|
-
# p.update_attribute :salary, SalaryCalculator.compute(p)
-
# end
-
# end
-
# ...
-
# end
-
#
-
# The phrase "Updating salaries..." would then be printed, along with the
-
# benchmark for the block when the block completes.
-
#
-
# == About the schema_migrations table
-
#
-
# Rails versions 2.0 and prior used to create a table called
-
# <tt>schema_info</tt> when using migrations. This table contained the
-
# version of the schema as of the last applied migration.
-
#
-
# Starting with Rails 2.1, the <tt>schema_info</tt> table is
-
# (automatically) replaced by the <tt>schema_migrations</tt> table, which
-
# contains the version numbers of all the migrations applied.
-
#
-
# As a result, it is now possible to add migration files that are numbered
-
# lower than the current schema version: when migrating up, those
-
# never-applied "interleaved" migrations will be automatically applied, and
-
# when migrating down, never-applied "interleaved" migrations will be skipped.
-
#
-
# == Timestamped Migrations
-
#
-
# By default, Rails generates migrations that look like:
-
#
-
# 20080717013526_your_migration_name.rb
-
#
-
# The prefix is a generation timestamp (in UTC).
-
#
-
# If you'd prefer to use numeric prefixes, you can turn timestamped migrations
-
# off by setting:
-
#
-
# config.active_record.timestamped_migrations = false
-
#
-
# In application.rb.
-
#
-
# == Reversible Migrations
-
#
-
# Starting with Rails 3.1, you will be able to define reversible migrations.
-
# Reversible migrations are migrations that know how to go +down+ for you.
-
# You simply supply the +up+ logic, and the Migration system will figure out
-
# how to execute the down commands for you.
-
#
-
# To define a reversible migration, define the +change+ method in your
-
# migration like this:
-
#
-
# class TenderloveMigration < ActiveRecord::Migration
-
# def change
-
# create_table(:horses) do |t|
-
# t.column :content, :text
-
# t.column :remind_at, :datetime
-
# end
-
# end
-
# end
-
#
-
# This migration will create the horses table for you on the way up, and
-
# automatically figure out how to drop the table on the way down.
-
#
-
# Some commands like +remove_column+ cannot be reversed. If you care to
-
# define how to move up and down in these cases, you should define the +up+
-
# and +down+ methods as before.
-
#
-
# If a command cannot be reversed, an
-
# <tt>ActiveRecord::IrreversibleMigration</tt> exception will be raised when
-
# the migration is moving down.
-
#
-
# For a list of commands that are reversible, please see
-
# <tt>ActiveRecord::Migration::CommandRecorder</tt>.
-
1
class Migration
-
1
autoload :CommandRecorder, 'active_record/migration/command_recorder'
-
-
-
# This class is used to verify that all migrations have been run before
-
# loading a web page if config.active_record.migration_error is set to :page_load
-
1
class CheckPending
-
1
def initialize(app)
-
@app = app
-
end
-
-
1
def call(env)
-
ActiveRecord::Base.logger.quietly do
-
ActiveRecord::Migration.check_pending!
-
end
-
@app.call(env)
-
end
-
end
-
-
1
class << self
-
1
attr_accessor :delegate # :nodoc:
-
end
-
-
1
def self.check_pending!
-
raise ActiveRecord::PendingMigrationError if ActiveRecord::Migrator.needs_migration?
-
end
-
-
1
def self.method_missing(name, *args, &block) # :nodoc:
-
35
(delegate || superclass.delegate).send(name, *args, &block)
-
end
-
-
1
def self.migrate(direction)
-
3
new.migrate direction
-
end
-
-
1
cattr_accessor :verbose
-
-
1
attr_accessor :name, :version
-
-
1
def initialize(name = self.class.name, version = nil)
-
89
@name = name
-
89
@version = version
-
89
@connection = nil
-
89
@reverting = false
-
end
-
-
# instantiate the delegate object after initialize is defined
-
1
self.verbose = true
-
1
self.delegate = new
-
-
1
def revert
-
3
@reverting = true
-
3
yield
-
ensure
-
3
@reverting = false
-
end
-
-
1
def reverting?
-
253
@reverting
-
end
-
-
1
def up
-
7
self.class.delegate = self
-
7
return unless self.class.respond_to?(:up)
-
6
self.class.up
-
end
-
-
1
def down
-
6
self.class.delegate = self
-
6
return unless self.class.respond_to?(:down)
-
5
self.class.down
-
end
-
-
# Execute this migration in the named direction
-
1
def migrate(direction)
-
76
return unless respond_to?(direction)
-
-
76
case direction
-
47
when :up then announce "migrating"
-
29
when :down then announce "reverting"
-
end
-
-
76
time = nil
-
76
ActiveRecord::Base.connection_pool.with_connection do |conn|
-
76
@connection = conn
-
76
if respond_to?(:change)
-
7
if direction == :down
-
3
recorder = CommandRecorder.new(@connection)
-
3
suppress_messages do
-
3
@connection = recorder
-
3
change
-
end
-
3
@connection = conn
-
3
time = Benchmark.measure {
-
3
self.revert {
-
3
recorder.inverse.each do |cmd, args|
-
2
send(cmd, *args)
-
end
-
}
-
}
-
else
-
8
time = Benchmark.measure { change }
-
end
-
else
-
138
time = Benchmark.measure { send(direction) }
-
end
-
75
@connection = nil
-
end
-
-
75
case direction
-
47
when :up then announce "migrated (%.4fs)" % time.real; write
-
28
when :down then announce "reverted (%.4fs)" % time.real; write
-
end
-
end
-
-
1
def write(text="")
-
690
puts(text) if verbose
-
end
-
-
1
def announce(message)
-
151
text = "#{version} #{name}: #{message}"
-
151
length = [0, 75 - text.length].max
-
151
write "== %s %s" % [text, "=" * length]
-
end
-
-
1
def say(message, subitem=false)
-
505
write "#{subitem ? " ->" : "--"} #{message}"
-
end
-
-
1
def say_with_time(message)
-
253
say(message)
-
253
result = nil
-
506
time = Benchmark.measure { result = yield }
-
252
say "%.4fs" % time.real, :subitem
-
252
say("#{result} rows", :subitem) if result.is_a?(Integer)
-
252
result
-
end
-
-
1
def suppress_messages
-
3
save, self.verbose = verbose, false
-
3
yield
-
ensure
-
3
self.verbose = save
-
end
-
-
1
def connection
-
507
@connection || ActiveRecord::Base.connection
-
end
-
-
1
def method_missing(method, *arguments, &block)
-
653
arg_list = arguments.map{ |a| a.inspect } * ', '
-
-
253
say_with_time "#{method}(#{arg_list})" do
-
253
unless reverting?
-
251
unless arguments.empty? || method == :execute
-
197
arguments[0] = Migrator.proper_table_name(arguments.first)
-
197
arguments[1] = Migrator.proper_table_name(arguments.second) if method == :rename_table
-
end
-
end
-
253
return super unless connection.respond_to?(method)
-
253
connection.send(method, *arguments, &block)
-
end
-
end
-
-
1
def copy(destination, sources, options = {})
-
15
copied = []
-
-
15
FileUtils.mkdir_p(destination) unless File.exists?(destination)
-
-
15
destination_migrations = ActiveRecord::Migrator.migrations(destination)
-
15
last = destination_migrations.last
-
15
sources.each do |scope, path|
-
20
source_migrations = ActiveRecord::Migrator.migrations(path)
-
-
20
source_migrations.each do |migration|
-
39
source = File.read(migration.filename)
-
39
source = "# This migration comes from #{scope} (originally #{migration.version})\n#{source}"
-
-
196
if duplicate = destination_migrations.detect { |m| m.name == migration.name }
-
17
if options[:on_skip] && duplicate.scope != scope.to_s
-
1
options[:on_skip].call(scope, migration)
-
end
-
17
next
-
end
-
-
22
migration.version = next_migration_number(last ? last.version + 1 : 0).to_i
-
22
new_path = File.join(destination, "#{migration.version}_#{migration.name.underscore}.#{scope}.rb")
-
22
old_path, migration.filename = migration.filename, new_path
-
22
last = migration
-
-
44
File.open(migration.filename, "w") { |f| f.write source }
-
22
copied << migration
-
22
options[:on_copy].call(scope, migration, old_path) if options[:on_copy]
-
22
destination_migrations << migration
-
end
-
end
-
-
15
copied
-
end
-
-
1
def next_migration_number(number)
-
22
if ActiveRecord::Base.timestamped_migrations
-
16
[Time.now.utc.strftime("%Y%m%d%H%M%S"), "%.14d" % number].max
-
else
-
6
"%.3d" % number
-
end
-
end
-
end
-
-
# MigrationProxy is used to defer loading of the actual migration classes
-
# until they are needed
-
1
class MigrationProxy < Struct.new(:name, :version, :filename, :scope)
-
-
1
def initialize(name, version, filename, scope)
-
135
super
-
135
@migration = nil
-
end
-
-
1
def basename
-
File.basename(filename)
-
end
-
-
1
delegate :migrate, :announce, :write, :to => :migration
-
-
1
private
-
-
1
def migration
-
8
@migration ||= load_migration
-
end
-
-
1
def load_migration
-
8
require(File.expand_path(filename))
-
8
name.constantize.new
-
end
-
-
end
-
-
1
class Migrator#:nodoc:
-
1
class << self
-
1
attr_writer :migrations_paths
-
1
alias :migrations_path= :migrations_paths=
-
-
1
def migrate(migrations_paths, target_version = nil, &block)
-
case
-
when target_version.nil?
-
4
up(migrations_paths, target_version, &block)
-
when current_version == 0 && target_version == 0
-
[]
-
when current_version > target_version
-
1
down(migrations_paths, target_version, &block)
-
else
-
2
up(migrations_paths, target_version, &block)
-
7
end
-
end
-
-
1
def rollback(migrations_paths, steps=1)
-
7
move(:down, migrations_paths, steps)
-
end
-
-
1
def forward(migrations_paths, steps=1)
-
2
move(:up, migrations_paths, steps)
-
end
-
-
1
def up(migrations_paths, target_version = nil)
-
11
migrations = migrations(migrations_paths)
-
14
migrations.select! { |m| yield m } if block_given?
-
-
11
self.new(:up, migrations, target_version).migrate
-
end
-
-
1
def down(migrations_paths, target_version = nil, &block)
-
9
migrations = migrations(migrations_paths)
-
12
migrations.select! { |m| yield m } if block_given?
-
-
9
self.new(:down, migrations, target_version).migrate
-
end
-
-
1
def run(direction, migrations_paths, target_version)
-
self.new(direction, migrations(migrations_paths), target_version).run
-
end
-
-
1
def open(migrations_paths)
-
self.new(:up, migrations(migrations_paths), nil)
-
end
-
-
1
def schema_migrations_table_name
-
80
SchemaMigration.table_name
-
end
-
-
1
def get_all_versions
-
203
SchemaMigration.all.map { |x| x.version.to_i }.sort
-
end
-
-
1
def current_version
-
56
sm_table = schema_migrations_table_name
-
56
if Base.connection.table_exists?(sm_table)
-
53
get_all_versions.max || 0
-
else
-
3
0
-
end
-
end
-
-
1
def needs_migration?
-
2
current_version < last_version
-
end
-
-
1
def last_version
-
4
migrations(migrations_paths).last.try(:version)||0
-
end
-
-
1
def proper_table_name(name)
-
# Use the Active Record objects own table_name, or pre/suffix from ActiveRecord::Base if name is a symbol/string
-
205
if name.respond_to? :table_name
-
3
name.table_name
-
else
-
202
"#{ActiveRecord::Base.table_name_prefix}#{name}#{ActiveRecord::Base.table_name_suffix}"
-
end
-
end
-
-
1
def migrations_paths
-
6
@migrations_paths ||= ['db/migrate']
-
# just to not break things if someone uses: migration_path = some_string
-
6
Array(@migrations_paths)
-
end
-
-
1
def migrations_path
-
migrations_paths.first
-
end
-
-
1
def migrations(paths)
-
48
paths = Array(paths)
-
-
97
files = Dir[*paths.map { |p| "#{p}/**/[0-9]*_*.rb" }]
-
-
48
migrations = files.map do |file|
-
135
version, name, scope = file.scan(/([0-9]+)_([_a-z0-9]*)\.?([_a-z0-9]*)?.rb/).first
-
-
135
raise IllegalMigrationNameError.new(file) unless version
-
135
version = version.to_i
-
135
name = name.camelize
-
-
135
MigrationProxy.new(name, version, file, scope)
-
end
-
-
48
migrations.sort_by(&:version)
-
end
-
-
1
private
-
-
1
def move(direction, migrations_paths, steps)
-
9
migrator = self.new(direction, migrations(migrations_paths))
-
9
start_index = migrator.migrations.index(migrator.current_migration)
-
-
9
if start_index
-
8
finish = migrator.migrations[start_index + steps]
-
8
version = finish ? finish.version : 0
-
8
send(direction, migrations_paths, version)
-
end
-
end
-
end
-
-
1
def initialize(direction, migrations, target_version = nil)
-
60
raise StandardError.new("This database does not yet support migrations") unless Base.connection.supports_migrations?
-
-
60
@direction = direction
-
60
@target_version = target_version
-
60
@migrated_versions = nil
-
-
60
if Array(migrations).grep(String).empty?
-
59
@migrations = migrations
-
else
-
1
ActiveSupport::Deprecation.warn "instantiate this class with a list of migrations"
-
1
@migrations = self.class.migrations(migrations)
-
end
-
-
60
validate(@migrations)
-
-
58
ActiveRecord::SchemaMigration.create_table
-
end
-
-
1
def current_version
-
54
migrated.sort.last || 0
-
end
-
-
1
def current_migration
-
80
migrations.detect { |m| m.version == current_version }
-
end
-
1
alias :current :current_migration
-
-
1
def run
-
13
target = migrations.detect { |m| m.version == @target_version }
-
4
raise UnknownMigrationVersionError.new(@target_version) if target.nil?
-
3
unless (up? && migrated.include?(target.version.to_i)) || (down? && !migrated.include?(target.version.to_i))
-
2
target.migrate(@direction)
-
2
record_version_state_after_migrating(target.version)
-
end
-
end
-
-
1
def migrate
-
43
if !target && @target_version && @target_version > 0
-
raise UnknownMigrationVersionError.new(@target_version)
-
end
-
-
43
running = runnable
-
-
43
if block_given?
-
message = "block argument to migrate is deprecated, please filter migrations before constructing the migrator"
-
ActiveSupport::Deprecation.warn message
-
running.select! { |m| yield m }
-
end
-
-
43
running.each do |migration|
-
64
Base.logger.info "Migrating to #{migration.name} (#{migration.version})" if Base.logger
-
-
64
begin
-
64
ddl_transaction do
-
64
migration.migrate(@direction)
-
63
record_version_state_after_migrating(migration.version)
-
end
-
rescue => e
-
1
canceled_msg = Base.connection.supports_ddl_transactions? ? "this and " : ""
-
1
raise StandardError, "An error has occurred, #{canceled_msg}all later migrations canceled:\n\n#{e}", e.backtrace
-
end
-
end
-
end
-
-
1
def runnable
-
43
runnable = migrations[start..finish]
-
43
if up?
-
76
runnable.reject { |m| ran?(m) }
-
else
-
# skip the last migration if we're headed down, but not ALL the way down
-
17
runnable.pop if target
-
43
runnable.find_all { |m| ran?(m) }
-
end
-
end
-
-
1
def migrations
-
279
down? ? @migrations.reverse : @migrations.sort_by(&:version)
-
end
-
-
1
def pending_migrations
-
1
already_migrated = migrated
-
3
migrations.reject { |m| already_migrated.include?(m.version) }
-
end
-
-
1
def migrated
-
199
@migrated_versions ||= Set.new(self.class.get_all_versions)
-
end
-
-
1
private
-
1
def ran?(migration)
-
76
migrated.include?(migration.version.to_i)
-
end
-
-
1
def target
-
344
migrations.detect { |m| m.version == @target_version }
-
end
-
-
1
def finish
-
43
migrations.index(target) || migrations.size - 1
-
end
-
-
1
def start
-
43
up? ? 0 : (migrations.index(current) || 0)
-
end
-
-
1
def validate(migrations)
-
134
name ,= migrations.group_by(&:name).find { |_,v| v.length > 1 }
-
60
raise DuplicateMigrationNameError.new(name) if name
-
-
223
version ,= migrations.group_by(&:version).find { |_,v| v.length > 1 }
-
59
raise DuplicateMigrationVersionError.new(version) if version
-
end
-
-
1
def record_version_state_after_migrating(version)
-
65
if down?
-
23
migrated.delete(version)
-
23
ActiveRecord::SchemaMigration.where(:version => version.to_s).delete_all
-
else
-
42
migrated << version
-
42
ActiveRecord::SchemaMigration.create!(:version => version.to_s)
-
end
-
end
-
-
1
def up?
-
89
@direction == :up
-
end
-
-
1
def down?
-
347
@direction == :down
-
end
-
-
# Wrap the migration in a transaction only if supported by the adapter.
-
1
def ddl_transaction
-
64
if Base.connection.supports_ddl_transactions?
-
128
Base.transaction { yield }
-
else
-
yield
-
end
-
end
-
end
-
end
-
1
module ActiveRecord
-
1
class Migration
-
# <tt>ActiveRecord::Migration::CommandRecorder</tt> records commands done during
-
# a migration and knows how to reverse those commands. The CommandRecorder
-
# knows how to invert the following commands:
-
#
-
# * add_column
-
# * add_index
-
# * add_timestamps
-
# * create_table
-
# * create_join_table
-
# * remove_timestamps
-
# * rename_column
-
# * rename_index
-
# * rename_table
-
1
class CommandRecorder
-
1
include JoinTable
-
-
1
attr_accessor :commands, :delegate
-
-
1
def initialize(delegate = nil)
-
31
@commands = []
-
31
@delegate = delegate
-
end
-
-
# record +command+. +command+ should be a method name and arguments.
-
# For example:
-
#
-
# recorder.record(:method_name, [:arg1, :arg2])
-
1
def record(*command)
-
28
@commands << command
-
end
-
-
# Returns a list that represents commands that are the inverse of the
-
# commands stored in +commands+. For example:
-
#
-
# recorder.record(:rename_table, [:old, :new])
-
# recorder.inverse # => [:rename_table, [:new, :old]]
-
#
-
# This method will raise an +IrreversibleMigration+ exception if it cannot
-
# invert the +commands+.
-
1
def inverse
-
24
@commands.reverse.map { |name, args|
-
26
method = :"invert_#{name}"
-
26
raise IrreversibleMigration unless respond_to?(method, true)
-
24
send(method, args)
-
}
-
end
-
-
1
def respond_to?(*args) # :nodoc:
-
32
super || delegate.respond_to?(*args)
-
end
-
-
1
[:create_table, :create_join_table, :change_table, :rename_table, :add_column, :remove_column, :rename_index, :rename_column, :add_index, :remove_index, :add_timestamps, :remove_timestamps, :change_column, :change_column_default, :add_reference, :remove_reference].each do |method|
-
16
class_eval <<-EOV, __FILE__, __LINE__ + 1
-
def #{method}(*args) # def create_table(*args)
-
record(:"#{method}", args) # record(:create_table, args)
-
end # end
-
EOV
-
end
-
1
alias :add_belongs_to :add_reference
-
1
alias :remove_belongs_to :remove_reference
-
-
1
private
-
-
1
def invert_create_table(args)
-
8
[:drop_table, [args.first]]
-
end
-
-
1
def invert_create_join_table(args)
-
2
table_name = find_join_table_name(*args)
-
-
2
[:drop_table, [table_name]]
-
end
-
-
1
def invert_rename_table(args)
-
2
[:rename_table, args.reverse]
-
end
-
-
1
def invert_add_column(args)
-
1
[:remove_column, args.first(2)]
-
end
-
-
1
def invert_rename_index(args)
-
1
[:rename_index, [args.first] + args.last(2).reverse]
-
end
-
-
1
def invert_rename_column(args)
-
1
[:rename_column, [args.first] + args.last(2).reverse]
-
end
-
-
1
def invert_add_index(args)
-
3
table, columns, options = *args
-
3
index_name = options.try(:[], :name)
-
3
options_hash = index_name ? {:name => index_name} : {:column => columns}
-
3
[:remove_index, [table, options_hash]]
-
end
-
-
1
def invert_remove_timestamps(args)
-
1
[:add_timestamps, args]
-
end
-
-
1
def invert_add_timestamps(args)
-
1
[:remove_timestamps, args]
-
end
-
-
1
def invert_add_reference(args)
-
2
[:remove_reference, args]
-
end
-
1
alias :invert_add_belongs_to :invert_add_reference
-
-
1
def invert_remove_reference(args)
-
2
[:add_reference, args]
-
end
-
1
alias :invert_remove_belongs_to :invert_remove_reference
-
-
# Forwards any missing method call to the \target.
-
1
def method_missing(method, *args, &block)
-
2
@delegate.send(method, *args, &block)
-
rescue NoMethodError => e
-
1
raise e, e.message.sub(/ for #<.*$/, " via proxy for #{@delegate}")
-
end
-
end
-
end
-
end
-
1
module ActiveRecord
-
1
class Migration
-
1
module JoinTable #:nodoc:
-
1
private
-
-
1
def find_join_table_name(table_1, table_2, options = {})
-
11
options.delete(:table_name) || join_table_name(table_1, table_2)
-
end
-
-
1
def join_table_name(table_1, table_2)
-
8
[table_1, table_2].sort.join("_").to_sym
-
end
-
end
-
end
-
end
-
1
module ActiveRecord
-
1
module ModelSchema
-
1
extend ActiveSupport::Concern
-
-
1
included do
-
##
-
# :singleton-method:
-
# Accessor for the prefix type that will be prepended to every primary key column name.
-
# The options are :table_name and :table_name_with_underscore. If the first is specified,
-
# the Product class will look for "productid" instead of "id" as the primary column. If the
-
# latter is specified, the Product class will look for "product_id" instead of "id". Remember
-
# that this is a global setting for all Active Records.
-
1
mattr_accessor :primary_key_prefix_type, instance_writer: false
-
-
##
-
# :singleton-method:
-
# Accessor for the name of the prefix string to prepend to every table name. So if set
-
# to "basecamp_", all table names will be named like "basecamp_projects", "basecamp_people",
-
# etc. This is a convenient way of creating a namespace for tables in a shared database.
-
# By default, the prefix is the empty string.
-
#
-
# If you are organising your models within modules you can add a prefix to the models within
-
# a namespace by defining a singleton method in the parent module called table_name_prefix which
-
# returns your chosen prefix.
-
1
class_attribute :table_name_prefix, instance_writer: false
-
1
self.table_name_prefix = ""
-
-
##
-
# :singleton-method:
-
# Works like +table_name_prefix+, but appends instead of prepends (set to "_basecamp" gives "projects_basecamp",
-
# "people_basecamp"). By default, the suffix is the empty string.
-
1
class_attribute :table_name_suffix, instance_writer: false
-
1
self.table_name_suffix = ""
-
-
##
-
# :singleton-method:
-
# Indicates whether table names should be the pluralized versions of the corresponding class names.
-
# If true, the default table name for a Product class will be +products+. If false, it would just be +product+.
-
# See table_name for the full rules on table/class naming. This is true, by default.
-
1
class_attribute :pluralize_table_names, instance_writer: false
-
1
self.pluralize_table_names = true
-
-
1
self.inheritance_column = 'type'
-
end
-
-
1
module ClassMethods
-
# Guesses the table name (in forced lower-case) based on the name of the class in the
-
# inheritance hierarchy descending directly from ActiveRecord::Base. So if the hierarchy
-
# looks like: Reply < Message < ActiveRecord::Base, then Message is used
-
# to guess the table name even when called on Reply. The rules used to do the guess
-
# are handled by the Inflector class in Active Support, which knows almost all common
-
# English inflections. You can add new inflections in config/initializers/inflections.rb.
-
#
-
# Nested classes are given table names prefixed by the singular form of
-
# the parent's table name. Enclosing modules are not considered.
-
#
-
# ==== Examples
-
#
-
# class Invoice < ActiveRecord::Base
-
# end
-
#
-
# file class table_name
-
# invoice.rb Invoice invoices
-
#
-
# class Invoice < ActiveRecord::Base
-
# class Lineitem < ActiveRecord::Base
-
# end
-
# end
-
#
-
# file class table_name
-
# invoice.rb Invoice::Lineitem invoice_lineitems
-
#
-
# module Invoice
-
# class Lineitem < ActiveRecord::Base
-
# end
-
# end
-
#
-
# file class table_name
-
# invoice/lineitem.rb Invoice::Lineitem lineitems
-
#
-
# Additionally, the class-level +table_name_prefix+ is prepended and the
-
# +table_name_suffix+ is appended. So if you have "myapp_" as a prefix,
-
# the table name guess for an Invoice class becomes "myapp_invoices".
-
# Invoice::Lineitem becomes "myapp_invoice_lineitems".
-
#
-
# You can also set your own table name explicitly:
-
#
-
# class Mouse < ActiveRecord::Base
-
# self.table_name = "mice"
-
# end
-
#
-
# Alternatively, you can override the table_name method to define your
-
# own computation. (Possibly using <tt>super</tt> to manipulate the default
-
# table name.) Example:
-
#
-
# class Post < ActiveRecord::Base
-
# def self.table_name
-
# "special_" + super
-
# end
-
# end
-
# Post.table_name # => "special_posts"
-
1
def table_name
-
20840
reset_table_name unless defined?(@table_name)
-
20840
@table_name
-
end
-
-
# Sets the table name explicitly. Example:
-
#
-
# class Project < ActiveRecord::Base
-
# self.table_name = "project"
-
# end
-
#
-
# You can also just define your own <tt>self.table_name</tt> method; see
-
# the documentation for ActiveRecord::Base#table_name.
-
1
def table_name=(value)
-
574
value = value && value.to_s
-
-
574
if defined?(@table_name)
-
150
return if value == @table_name
-
50
reset_column_information if connected?
-
end
-
-
474
@table_name = value
-
474
@quoted_table_name = nil
-
474
@arel_table = nil
-
474
@sequence_name = nil unless defined?(@explicit_sequence_name) && @explicit_sequence_name
-
474
@relation = Relation.new(self, arel_table)
-
end
-
-
# Returns a quoted version of the table name, used to construct SQL statements.
-
1
def quoted_table_name
-
102
@quoted_table_name ||= connection.quote_table_name(table_name)
-
end
-
-
# Computes the table name, (re)sets it internally, and returns it.
-
1
def reset_table_name #:nodoc:
-
387
self.table_name = if abstract_class?
-
7
superclass == Base ? nil : superclass.table_name
-
elsif superclass.abstract_class?
-
9
superclass.table_name || compute_table_name
-
else
-
371
compute_table_name
-
end
-
end
-
-
1
def full_table_name_prefix #:nodoc:
-
750
(parents.detect{ |p| p.respond_to?(:table_name_prefix) } || self).table_name_prefix
-
end
-
-
# Defines the name of the table column which will store the class name on single-table
-
# inheritance situations.
-
#
-
# The default inheritance column name is +type+, which means it's a
-
# reserved word inside Active Record. To be able to use single-table
-
# inheritance with another column name, or to use the column +type+ in
-
# your own model for something else, you can set +inheritance_column+:
-
#
-
# self.inheritance_column = 'zoink'
-
1
def inheritance_column
-
56204
(@inheritance_column ||= nil) || superclass.inheritance_column
-
end
-
-
# Sets the value of inheritance_column
-
1
def inheritance_column=(value)
-
3
@inheritance_column = value.to_s
-
3
@explicit_inheritance_column = true
-
end
-
-
1
def sequence_name
-
7
if base_class == self
-
7
@sequence_name ||= reset_sequence_name
-
else
-
(@sequence_name ||= nil) || base_class.sequence_name
-
end
-
end
-
-
1
def reset_sequence_name #:nodoc:
-
55
@explicit_sequence_name = false
-
55
@sequence_name = connection.default_sequence_name(table_name, primary_key)
-
end
-
-
# Sets the name of the sequence to use when generating ids to the given
-
# value, or (if the value is nil or false) to the value returned by the
-
# given block. This is required for Oracle and is useful for any
-
# database which relies on sequences for primary key generation.
-
#
-
# If a sequence name is not explicitly set when using Oracle or Firebird,
-
# it will default to the commonly used pattern of: #{table_name}_seq
-
#
-
# If a sequence name is not explicitly set when using PostgreSQL, it
-
# will discover the sequence corresponding to your primary key for you.
-
#
-
# class Project < ActiveRecord::Base
-
# self.sequence_name = "projectseq" # default would have been "project_seq"
-
# end
-
1
def sequence_name=(value)
-
2
@sequence_name = value.to_s
-
2
@explicit_sequence_name = true
-
end
-
-
# Indicates whether the table associated with this class exists
-
1
def table_exists?
-
469
connection.schema_cache.table_exists?(table_name)
-
end
-
-
# Returns an array of column objects for the table associated with this class.
-
1
def columns
-
@columns ||= connection.schema_cache.columns[table_name].map do |col|
-
2830
col = col.dup
-
2830
col.primary = (col.name == primary_key)
-
2830
col
-
2167
end
-
end
-
-
# Returns a hash of column objects for the table associated with this class.
-
1
def columns_hash
-
65975
@columns_hash ||= Hash[columns.map { |c| [c.name, c] }]
-
end
-
-
1
def column_types # :nodoc:
-
13735
@column_types ||= decorate_columns(columns_hash.dup)
-
end
-
-
1
def decorate_columns(columns_hash) # :nodoc:
-
11054
return if columns_hash.empty?
-
-
10328
serialized_attributes.each_key do |key|
-
1140
columns_hash[key] = AttributeMethods::Serialization::Type.new(columns_hash[key])
-
end
-
-
10328
columns_hash.each do |name, col|
-
79701
if create_time_zone_conversion_attribute?(name, col)
-
76
columns_hash[name] = AttributeMethods::TimeZoneConversion::Type.new(col)
-
end
-
end
-
-
10328
columns_hash
-
end
-
-
# Returns a hash where the keys are column names and the values are
-
# default values when instantiating the AR object for this table.
-
1
def column_defaults
-
1978
@column_defaults ||= Hash[columns.map { |c| [c.name, c.default] }]
-
end
-
-
# Returns an array of column names as strings.
-
1
def column_names
-
4936
@column_names ||= columns.map { |column| column.name }
-
end
-
-
# Returns an array of column objects where the primary id, all columns ending in "_id" or "_count",
-
# and columns used for single table inheritance have been removed.
-
1
def content_columns
-
18
@content_columns ||= columns.reject { |c| c.primary || c.name =~ /(_id|_count)$/ || c.name == inheritance_column }
-
end
-
-
# Returns a hash of all the methods added to query each of the columns in the table with the name of the method as the key
-
# and true as the value. This makes it possible to do O(1) lookups in respond_to? to check if a given method for attribute
-
# is available.
-
1
def column_methods_hash #:nodoc:
-
@dynamic_methods_hash ||= column_names.each_with_object(Hash.new(false)) do |attr, methods|
-
81
attr_name = attr.to_s
-
81
methods[attr.to_sym] = attr_name
-
81
methods["#{attr}=".to_sym] = attr_name
-
81
methods["#{attr}?".to_sym] = attr_name
-
81
methods["#{attr}_before_type_cast".to_sym] = attr_name
-
11
end
-
end
-
-
# Resets all the cached information about columns, which will cause them
-
# to be reloaded on the next request.
-
#
-
# The most common usage pattern for this method is probably in a migration,
-
# when just after creating a table you want to populate it with some default
-
# values, eg:
-
#
-
# class CreateJobLevels < ActiveRecord::Migration
-
# def up
-
# create_table :job_levels do |t|
-
# t.integer :id
-
# t.string :name
-
#
-
# t.timestamps
-
# end
-
#
-
# JobLevel.reset_column_information
-
# %w{assistant executive manager director}.each do |type|
-
# JobLevel.create(:name => type)
-
# end
-
# end
-
#
-
# def down
-
# drop_table :job_levels
-
# end
-
# end
-
1
def reset_column_information
-
208
connection.clear_cache!
-
208
undefine_attribute_methods
-
208
connection.schema_cache.clear_table_cache!(table_name) if table_exists?
-
-
208
@arel_engine = nil
-
208
@column_defaults = nil
-
208
@column_names = nil
-
208
@columns = nil
-
208
@columns_hash = nil
-
208
@column_types = nil
-
208
@content_columns = nil
-
208
@dynamic_methods_hash = nil
-
208
@inheritance_column = nil unless defined?(@explicit_inheritance_column) && @explicit_inheritance_column
-
208
@relation = nil
-
end
-
-
# This is a hook for use by modules that need to do extra stuff to
-
# attributes when they are initialized. (e.g. attribute
-
# serialization)
-
1
def initialize_attributes(attributes, options = {}) #:nodoc:
-
13827
attributes
-
end
-
-
1
private
-
-
# Guesses the table name, but does not decorate it with prefix and suffix information.
-
1
def undecorated_table_name(class_name = base_class.name)
-
289
table_name = class_name.to_s.demodulize.underscore
-
289
pluralize_table_names ? table_name.pluralize : table_name
-
end
-
-
# Computes and returns a table name according to default conventions.
-
1
def compute_table_name
-
378
base = base_class
-
378
if self == base
-
# Nested classes are prefixed with singular parent table name.
-
289
if parent < Base && !parent.abstract_class?
-
16
contained = parent.table_name
-
16
contained = contained.singularize if parent.pluralize_table_names
-
16
contained += '_'
-
end
-
289
"#{full_table_name_prefix}#{contained}#{undecorated_table_name(name)}#{table_name_suffix}"
-
else
-
# STI subclasses always use their superclass' table.
-
89
base.table_name
-
end
-
end
-
end
-
end
-
end
-
1
require 'active_support/core_ext/hash/except'
-
1
require 'active_support/core_ext/object/try'
-
1
require 'active_support/core_ext/hash/indifferent_access'
-
-
1
module ActiveRecord
-
1
module NestedAttributes #:nodoc:
-
1
class TooManyRecords < ActiveRecordError
-
end
-
-
1
extend ActiveSupport::Concern
-
-
1
included do
-
1
class_attribute :nested_attributes_options, instance_writer: false
-
1
self.nested_attributes_options = {}
-
end
-
-
# = Active Record Nested Attributes
-
#
-
# Nested attributes allow you to save attributes on associated records
-
# through the parent. By default nested attribute updating is turned off
-
# and you can enable it using the accepts_nested_attributes_for class
-
# method. When you enable nested attributes an attribute writer is
-
# defined on the model.
-
#
-
# The attribute writer is named after the association, which means that
-
# in the following example, two new methods are added to your model:
-
#
-
# <tt>author_attributes=(attributes)</tt> and
-
# <tt>pages_attributes=(attributes)</tt>.
-
#
-
# class Book < ActiveRecord::Base
-
# has_one :author
-
# has_many :pages
-
#
-
# accepts_nested_attributes_for :author, :pages
-
# end
-
#
-
# Note that the <tt>:autosave</tt> option is automatically enabled on every
-
# association that accepts_nested_attributes_for is used for.
-
#
-
# === One-to-one
-
#
-
# Consider a Member model that has one Avatar:
-
#
-
# class Member < ActiveRecord::Base
-
# has_one :avatar
-
# accepts_nested_attributes_for :avatar
-
# end
-
#
-
# Enabling nested attributes on a one-to-one association allows you to
-
# create the member and avatar in one go:
-
#
-
# params = { :member => { :name => 'Jack', :avatar_attributes => { :icon => 'smiling' } } }
-
# member = Member.create(params[:member])
-
# member.avatar.id # => 2
-
# member.avatar.icon # => 'smiling'
-
#
-
# It also allows you to update the avatar through the member:
-
#
-
# params = { :member => { :avatar_attributes => { :id => '2', :icon => 'sad' } } }
-
# member.update_attributes params[:member]
-
# member.avatar.icon # => 'sad'
-
#
-
# By default you will only be able to set and update attributes on the
-
# associated model. If you want to destroy the associated model through the
-
# attributes hash, you have to enable it first using the
-
# <tt>:allow_destroy</tt> option.
-
#
-
# class Member < ActiveRecord::Base
-
# has_one :avatar
-
# accepts_nested_attributes_for :avatar, :allow_destroy => true
-
# end
-
#
-
# Now, when you add the <tt>_destroy</tt> key to the attributes hash, with a
-
# value that evaluates to +true+, you will destroy the associated model:
-
#
-
# member.avatar_attributes = { :id => '2', :_destroy => '1' }
-
# member.avatar.marked_for_destruction? # => true
-
# member.save
-
# member.reload.avatar # => nil
-
#
-
# Note that the model will _not_ be destroyed until the parent is saved.
-
#
-
# === One-to-many
-
#
-
# Consider a member that has a number of posts:
-
#
-
# class Member < ActiveRecord::Base
-
# has_many :posts
-
# accepts_nested_attributes_for :posts
-
# end
-
#
-
# You can now set or update attributes on an associated post model through
-
# the attribute hash.
-
#
-
# For each hash that does _not_ have an <tt>id</tt> key a new record will
-
# be instantiated, unless the hash also contains a <tt>_destroy</tt> key
-
# that evaluates to +true+.
-
#
-
# params = { :member => {
-
# :name => 'joe', :posts_attributes => [
-
# { :title => 'Kari, the awesome Ruby documentation browser!' },
-
# { :title => 'The egalitarian assumption of the modern citizen' },
-
# { :title => '', :_destroy => '1' } # this will be ignored
-
# ]
-
# }}
-
#
-
# member = Member.create(params[:member])
-
# member.posts.length # => 2
-
# member.posts.first.title # => 'Kari, the awesome Ruby documentation browser!'
-
# member.posts.second.title # => 'The egalitarian assumption of the modern citizen'
-
#
-
# You may also set a :reject_if proc to silently ignore any new record
-
# hashes if they fail to pass your criteria. For example, the previous
-
# example could be rewritten as:
-
#
-
# class Member < ActiveRecord::Base
-
# has_many :posts
-
# accepts_nested_attributes_for :posts, :reject_if => proc { |attributes| attributes['title'].blank? }
-
# end
-
#
-
# params = { :member => {
-
# :name => 'joe', :posts_attributes => [
-
# { :title => 'Kari, the awesome Ruby documentation browser!' },
-
# { :title => 'The egalitarian assumption of the modern citizen' },
-
# { :title => '' } # this will be ignored because of the :reject_if proc
-
# ]
-
# }}
-
#
-
# member = Member.create(params[:member])
-
# member.posts.length # => 2
-
# member.posts.first.title # => 'Kari, the awesome Ruby documentation browser!'
-
# member.posts.second.title # => 'The egalitarian assumption of the modern citizen'
-
#
-
# Alternatively, :reject_if also accepts a symbol for using methods:
-
#
-
# class Member < ActiveRecord::Base
-
# has_many :posts
-
# accepts_nested_attributes_for :posts, :reject_if => :new_record?
-
# end
-
#
-
# class Member < ActiveRecord::Base
-
# has_many :posts
-
# accepts_nested_attributes_for :posts, :reject_if => :reject_posts
-
#
-
# def reject_posts(attributed)
-
# attributed['title'].blank?
-
# end
-
# end
-
#
-
# If the hash contains an <tt>id</tt> key that matches an already
-
# associated record, the matching record will be modified:
-
#
-
# member.attributes = {
-
# :name => 'Joe',
-
# :posts_attributes => [
-
# { :id => 1, :title => '[UPDATED] An, as of yet, undisclosed awesome Ruby documentation browser!' },
-
# { :id => 2, :title => '[UPDATED] other post' }
-
# ]
-
# }
-
#
-
# member.posts.first.title # => '[UPDATED] An, as of yet, undisclosed awesome Ruby documentation browser!'
-
# member.posts.second.title # => '[UPDATED] other post'
-
#
-
# By default the associated records are protected from being destroyed. If
-
# you want to destroy any of the associated records through the attributes
-
# hash, you have to enable it first using the <tt>:allow_destroy</tt>
-
# option. This will allow you to also use the <tt>_destroy</tt> key to
-
# destroy existing records:
-
#
-
# class Member < ActiveRecord::Base
-
# has_many :posts
-
# accepts_nested_attributes_for :posts, :allow_destroy => true
-
# end
-
#
-
# params = { :member => {
-
# :posts_attributes => [{ :id => '2', :_destroy => '1' }]
-
# }}
-
#
-
# member.attributes = params[:member]
-
# member.posts.detect { |p| p.id == 2 }.marked_for_destruction? # => true
-
# member.posts.length # => 2
-
# member.save
-
# member.reload.posts.length # => 1
-
#
-
# === Saving
-
#
-
# All changes to models, including the destruction of those marked for
-
# destruction, are saved and destroyed automatically and atomically when
-
# the parent model is saved. This happens inside the transaction initiated
-
# by the parents save method. See ActiveRecord::AutosaveAssociation.
-
#
-
# === Validating the presence of a parent model
-
#
-
# If you want to validate that a child record is associated with a parent
-
# record, you can use <tt>validates_presence_of</tt> and
-
# <tt>inverse_of</tt> as this example illustrates:
-
#
-
# class Member < ActiveRecord::Base
-
# has_many :posts, :inverse_of => :member
-
# accepts_nested_attributes_for :posts
-
# end
-
#
-
# class Post < ActiveRecord::Base
-
# belongs_to :member, :inverse_of => :posts
-
# validates_presence_of :member
-
# end
-
1
module ClassMethods
-
10
REJECT_ALL_BLANK_PROC = proc { |attributes| attributes.all? { |key, value| key == '_destroy' || value.blank? } }
-
-
# Defines an attributes writer for the specified association(s).
-
#
-
# Supported options:
-
# [:allow_destroy]
-
# If true, destroys any members from the attributes hash with a
-
# <tt>_destroy</tt> key and a value that evaluates to +true+
-
# (eg. 1, '1', true, or 'true'). This option is off by default.
-
# [:reject_if]
-
# Allows you to specify a Proc or a Symbol pointing to a method
-
# that checks whether a record should be built for a certain attribute
-
# hash. The hash is passed to the supplied Proc or the method
-
# and it should return either +true+ or +false+. When no :reject_if
-
# is specified, a record will be built for all attribute hashes that
-
# do not have a <tt>_destroy</tt> value that evaluates to true.
-
# Passing <tt>:all_blank</tt> instead of a Proc will create a proc
-
# that will reject a record where all the attributes are blank excluding
-
# any value for _destroy.
-
# [:limit]
-
# Allows you to specify the maximum number of the associated records that
-
# can be processed with the nested attributes. Limit also can be specified as a
-
# Proc or a Symbol pointing to a method that should return number. If the size of the
-
# nested attributes array exceeds the specified limit, NestedAttributes::TooManyRecords
-
# exception is raised. If omitted, any number associations can be processed.
-
# Note that the :limit option is only applicable to one-to-many associations.
-
# [:update_only]
-
# For a one-to-one association, this option allows you to specify how
-
# nested attributes are to be used when an associated record already
-
# exists. In general, an existing record may either be updated with the
-
# new set of attribute values or be replaced by a wholly new record
-
# containing those values. By default the :update_only option is +false+
-
# and the nested attributes are used to update the existing record only
-
# if they include the record's <tt>:id</tt> value. Otherwise a new
-
# record will be instantiated and used to replace the existing one.
-
# However if the :update_only option is +true+, the nested attributes
-
# are used to update the record's attributes always, regardless of
-
# whether the <tt>:id</tt> is present. The option is ignored for collection
-
# associations.
-
#
-
# Examples:
-
# # creates avatar_attributes=
-
# accepts_nested_attributes_for :avatar, :reject_if => proc { |attributes| attributes['name'].blank? }
-
# # creates avatar_attributes=
-
# accepts_nested_attributes_for :avatar, :reject_if => :all_blank
-
# # creates avatar_attributes= and posts_attributes=
-
# accepts_nested_attributes_for :avatar, :posts, :allow_destroy => true
-
1
def accepts_nested_attributes_for(*attr_names)
-
82
options = { :allow_destroy => false, :update_only => false }
-
82
options.update(attr_names.extract_options!)
-
82
options.assert_valid_keys(:allow_destroy, :reject_if, :limit, :update_only)
-
82
options[:reject_if] = REJECT_ALL_BLANK_PROC if options[:reject_if] == :all_blank
-
-
82
attr_names.each do |association_name|
-
90
if reflection = reflect_on_association(association_name)
-
89
reflection.options[:autosave] = true
-
89
add_autosave_association_callbacks(reflection)
-
-
89
nested_attributes_options = self.nested_attributes_options.dup
-
89
nested_attributes_options[association_name.to_sym] = options
-
89
self.nested_attributes_options = nested_attributes_options
-
-
89
type = (reflection.collection? ? :collection : :one_to_one)
-
-
# def pirate_attributes=(attributes)
-
# assign_nested_attributes_for_one_to_one_association(:pirate, attributes, mass_assignment_options)
-
# end
-
89
generated_feature_methods.module_eval <<-eoruby, __FILE__, __LINE__ + 1
-
if method_defined?(:#{association_name}_attributes=)
-
remove_method(:#{association_name}_attributes=)
-
end
-
def #{association_name}_attributes=(attributes)
-
assign_nested_attributes_for_#{type}_association(:#{association_name}, attributes)
-
end
-
eoruby
-
else
-
1
raise ArgumentError, "No association found for name `#{association_name}'. Has it been defined yet?"
-
end
-
end
-
end
-
end
-
-
# Returns ActiveRecord::AutosaveAssociation::marked_for_destruction? It's
-
# used in conjunction with fields_for to build a form element for the
-
# destruction of this association.
-
#
-
# See ActionView::Helpers::FormHelper::fields_for for more info.
-
1
def _destroy
-
2
marked_for_destruction?
-
end
-
-
1
private
-
-
# Attribute hash keys that should not be assigned as normal attributes.
-
# These hash keys are nested attributes implementation details.
-
1
UNASSIGNABLE_KEYS = %w( id _destroy )
-
-
# Assigns the given attributes to the association.
-
#
-
# If an associated record does not yet exist, one will be instantiated. If
-
# an associated record already exists, the method's behavior depends on
-
# the value of the update_only option. If update_only is +false+ and the
-
# given attributes include an <tt>:id</tt> that matches the existing record's
-
# id, then the existing record will be modified. If no <tt>:id</tt> is provided
-
# it will be replaced with a new record. If update_only is +true+ the existing
-
# record will be modified regardless of whether an <tt>:id</tt> is provided.
-
#
-
# If the given attributes include a matching <tt>:id</tt> attribute, or
-
# update_only is true, and a <tt>:_destroy</tt> key set to a truthy value,
-
# then the existing record will be marked for destruction.
-
1
def assign_nested_attributes_for_one_to_one_association(association_name, attributes)
-
71
options = self.nested_attributes_options[association_name]
-
71
attributes = attributes.with_indifferent_access
-
-
71
if (options[:update_only] || !attributes['id'].blank?) && (record = send(association_name)) &&
-
(options[:update_only] || record.id.to_s == attributes['id'].to_s)
-
43
assign_to_or_mark_for_destruction(record, attributes, options[:allow_destroy]) unless call_reject_if(association_name, attributes)
-
-
28
elsif attributes['id'].present?
-
2
raise_nested_attributes_record_not_found(association_name, attributes['id'])
-
-
26
elsif !reject_new_record?(association_name, attributes)
-
17
method = "build_#{association_name}"
-
17
if respond_to?(method)
-
16
send(method, attributes.except(*UNASSIGNABLE_KEYS))
-
else
-
1
raise ArgumentError, "Cannot build association `#{association_name}'. Are you trying to build a polymorphic one-to-one association?"
-
end
-
end
-
end
-
-
# Assigns the given attributes to the collection association.
-
#
-
# Hashes with an <tt>:id</tt> value matching an existing associated record
-
# will update that record. Hashes without an <tt>:id</tt> value will build
-
# a new record for the association. Hashes with a matching <tt>:id</tt>
-
# value and a <tt>:_destroy</tt> key set to a truthy value will mark the
-
# matched record for destruction.
-
#
-
# For example:
-
#
-
# assign_nested_attributes_for_collection_association(:people, {
-
# '1' => { :id => '1', :name => 'Peter' },
-
# '2' => { :name => 'John' },
-
# '3' => { :id => '2', :_destroy => true }
-
# })
-
#
-
# Will update the name of the Person with ID 1, build a new associated
-
# person with the name 'John', and mark the associated Person with ID 2
-
# for destruction.
-
#
-
# Also accepts an Array of attribute hashes:
-
#
-
# assign_nested_attributes_for_collection_association(:people, [
-
# { :id => '1', :name => 'Peter' },
-
# { :name => 'John' },
-
# { :id => '2', :_destroy => true }
-
# ])
-
1
def assign_nested_attributes_for_collection_association(association_name, attributes_collection)
-
105
options = self.nested_attributes_options[association_name]
-
-
105
unless attributes_collection.is_a?(Hash) || attributes_collection.is_a?(Array)
-
2
raise ArgumentError, "Hash or Array expected, got #{attributes_collection.class.name} (#{attributes_collection.inspect})"
-
end
-
-
103
if limit = options[:limit]
-
9
limit = case limit
-
when Symbol
-
3
send(limit)
-
when Proc
-
3
limit.call
-
else
-
3
limit
-
end
-
-
9
if limit && attributes_collection.size > limit
-
3
raise TooManyRecords, "Maximum #{limit} records are allowed. Got #{attributes_collection.size} records instead."
-
end
-
end
-
-
100
if attributes_collection.is_a? Hash
-
63
keys = attributes_collection.keys
-
63
attributes_collection = if keys.include?('id') || keys.include?(:id)
-
5
[attributes_collection]
-
else
-
58
attributes_collection.values
-
end
-
end
-
-
100
association = association(association_name)
-
-
100
existing_records = if association.loaded?
-
41
association.target
-
else
-
147
attribute_ids = attributes_collection.map {|a| a['id'] || a[:id] }.compact
-
59
attribute_ids.empty? ? [] : association.scope.where(association.klass.primary_key => attribute_ids)
-
end
-
-
100
attributes_collection.each do |attributes|
-
160
attributes = attributes.with_indifferent_access
-
-
160
if attributes['id'].blank?
-
46
unless reject_new_record?(association_name, attributes)
-
40
association.build(attributes.except(*UNASSIGNABLE_KEYS))
-
end
-
167
elsif existing_record = existing_records.detect { |record| record.id.to_s == attributes['id'].to_s }
-
112
unless association.loaded? || call_reject_if(association_name, attributes)
-
# Make sure we are operating on the actual object which is in the association's
-
# proxy_target array (either by finding it, or adding it if not found)
-
103
target_record = association.target.detect { |record| record == existing_record }
-
-
53
if target_record
-
25
existing_record = target_record
-
else
-
28
association.add_to_target(existing_record)
-
end
-
end
-
-
112
if !call_reject_if(association_name, attributes)
-
111
assign_to_or_mark_for_destruction(existing_record, attributes, options[:allow_destroy])
-
end
-
else
-
2
raise_nested_attributes_record_not_found(association_name, attributes['id'])
-
end
-
end
-
end
-
-
# Updates a record with the +attributes+ or marks it for destruction if
-
# +allow_destroy+ is +true+ and has_destroy_flag? returns +true+.
-
1
def assign_to_or_mark_for_destruction(record, attributes, allow_destroy)
-
153
record.assign_attributes(attributes.except(*UNASSIGNABLE_KEYS))
-
153
record.mark_for_destruction if has_destroy_flag?(attributes) && allow_destroy
-
end
-
-
# Determines if a hash contains a truthy _destroy key.
-
1
def has_destroy_flag?(hash)
-
500
ConnectionAdapters::Column.value_to_boolean(hash['_destroy'])
-
end
-
-
# Determines if a new record should be build by checking for
-
# has_destroy_flag? or if a <tt>:reject_if</tt> proc exists for this
-
# association and evaluates to +true+.
-
1
def reject_new_record?(association_name, attributes)
-
72
has_destroy_flag?(attributes) || call_reject_if(association_name, attributes)
-
end
-
-
1
def call_reject_if(association_name, attributes)
-
275
return false if has_destroy_flag?(attributes)
-
229
case callback = self.nested_attributes_options[association_name][:reject_if]
-
when Symbol
-
3
method(callback).arity == 0 ? send(callback) : send(callback, attributes)
-
when Proc
-
158
callback.call(attributes)
-
end
-
end
-
-
1
def raise_nested_attributes_record_not_found(association_name, record_id)
-
4
raise RecordNotFound, "Couldn't find #{self.class.reflect_on_association(association_name).klass.name} with ID=#{record_id} for #{self.class.name} with ID=#{id}"
-
end
-
end
-
end
-
# -*- coding: utf-8 -*-
-
-
1
module ActiveRecord
-
1
module NullRelation # :nodoc:
-
1
def exec_queries
-
4
@records = []
-
end
-
-
1
def pluck(_column_name)
-
2
[]
-
end
-
-
1
def delete_all(_conditions = nil)
-
1
0
-
end
-
-
1
def update_all(_updates, _conditions = nil, _options = {})
-
1
0
-
end
-
-
1
def delete(_id_or_array)
-
1
0
-
end
-
-
1
def size
-
1
0
-
end
-
-
1
def empty?
-
1
true
-
end
-
-
1
def any?
-
1
false
-
end
-
-
1
def many?
-
1
false
-
end
-
-
1
def to_sql
-
1
@to_sql ||= ""
-
end
-
-
1
def where_values_hash
-
87
{}
-
end
-
-
1
def count(*)
-
5
0
-
end
-
-
1
def sum(*)
-
1
0
-
end
-
-
1
def calculate(_operation, _column_name, _options = {})
-
nil
-
end
-
-
1
def exists?(_id = false)
-
1
false
-
end
-
end
-
end
-
-
1
module ActiveRecord
-
# = Active Record Observer
-
#
-
# Observer classes respond to life cycle callbacks to implement trigger-like
-
# behavior outside the original class. This is a great way to reduce the
-
# clutter that normally comes when the model class is burdened with
-
# functionality that doesn't pertain to the core responsibility of the
-
# class. Example:
-
#
-
# class CommentObserver < ActiveRecord::Observer
-
# def after_save(comment)
-
# Notifications.comment("admin@do.com", "New comment was posted", comment).deliver
-
# end
-
# end
-
#
-
# This Observer sends an email when a Comment#save is finished.
-
#
-
# class ContactObserver < ActiveRecord::Observer
-
# def after_create(contact)
-
# contact.logger.info('New contact added!')
-
# end
-
#
-
# def after_destroy(contact)
-
# contact.logger.warn("Contact with an id of #{contact.id} was destroyed!")
-
# end
-
# end
-
#
-
# This Observer uses logger to log when specific callbacks are triggered.
-
#
-
# == Observing a class that can't be inferred
-
#
-
# Observers will by default be mapped to the class with which they share a name. So CommentObserver will
-
# be tied to observing Comment, ProductManagerObserver to ProductManager, and so on. If you want to name your observer
-
# differently than the class you're interested in observing, you can use the Observer.observe class method which takes
-
# either the concrete class (Product) or a symbol for that class (:product):
-
#
-
# class AuditObserver < ActiveRecord::Observer
-
# observe :account
-
#
-
# def after_update(account)
-
# AuditTrail.new(account, "UPDATED")
-
# end
-
# end
-
#
-
# If the audit observer needs to watch more than one kind of object, this can be specified with multiple arguments:
-
#
-
# class AuditObserver < ActiveRecord::Observer
-
# observe :account, :balance
-
#
-
# def after_update(record)
-
# AuditTrail.new(record, "UPDATED")
-
# end
-
# end
-
#
-
# The AuditObserver will now act on both updates to Account and Balance by treating them both as records.
-
#
-
# == Available callback methods
-
#
-
# The observer can implement callback methods for each of the methods described in the Callbacks module.
-
#
-
# == Storing Observers in Rails
-
#
-
# If you're using Active Record within Rails, observer classes are usually stored in app/models with the
-
# naming convention of app/models/audit_observer.rb.
-
#
-
# == Configuration
-
#
-
# In order to activate an observer, list it in the <tt>config.active_record.observers</tt> configuration
-
# setting in your <tt>config/application.rb</tt> file.
-
#
-
# config.active_record.observers = :comment_observer, :signup_observer
-
#
-
# Observers will not be invoked unless you define these in your application configuration.
-
#
-
# If you are using Active Record outside Rails, activate the observers explicitly in a configuration or
-
# environment file:
-
#
-
# ActiveRecord::Base.add_observer CommentObserver.instance
-
# ActiveRecord::Base.add_observer SignupObserver.instance
-
#
-
# == Loading
-
#
-
# Observers register themselves in the model class they observe, since it is the class that
-
# notifies them of events when they occur. As a side-effect, when an observer is loaded its
-
# corresponding model class is loaded.
-
#
-
# Up to (and including) Rails 2.0.2 observers were instantiated between plugins and
-
# application initializers. Now observers are loaded after application initializers,
-
# so observed models can make use of extensions.
-
#
-
# If by any chance you are using observed models in the initialization you can still
-
# load their observers by calling <tt>ModelObserver.instance</tt> before. Observers are
-
# singletons and that call instantiates and registers them.
-
#
-
1
class Observer < ActiveModel::Observer
-
-
1
protected
-
-
1
def observed_classes
-
18
klasses = super
-
126
klasses + klasses.map { |klass| klass.descendants }.flatten
-
end
-
-
1
def add_observer!(klass)
-
61
super
-
61
define_callbacks klass
-
end
-
-
1
def define_callbacks(klass)
-
61
observer = self
-
61
observer_name = observer.class.name.underscore.gsub('/', '__')
-
-
61
ActiveRecord::Callbacks::CALLBACKS.each do |callback|
-
1159
next unless respond_to?(callback)
-
79
callback_meth = :"_notify_#{observer_name}_for_#{callback}"
-
79
unless klass.respond_to?(callback_meth)
-
79
klass.send(:define_method, callback_meth) do |&block|
-
2130
observer.update(callback, self, &block)
-
end
-
79
klass.send(callback, callback_meth)
-
end
-
end
-
end
-
end
-
end
-
1
module ActiveRecord
-
# = Active Record Persistence
-
1
module Persistence
-
1
extend ActiveSupport::Concern
-
-
1
module ClassMethods
-
# Creates an object (or multiple objects) and saves it to the database, if validations pass.
-
# The resulting object is returned whether the object was saved successfully to the database or not.
-
#
-
# The +attributes+ parameter can be either a Hash or an Array of Hashes. These Hashes describe the
-
# attributes on the objects that are to be created.
-
#
-
# +create+ respects mass-assignment security and accepts either +:as+ or +:without_protection+ options
-
# in the +options+ parameter.
-
#
-
# ==== Examples
-
# # Create a single new object
-
# User.create(first_name: 'Jamie')
-
#
-
# # Create an Array of new objects
-
# User.create([{ first_name: 'Jamie' }, { first_name: 'Jeremy' }])
-
#
-
# # Create a single object and pass it into a block to set other attributes.
-
# User.create(first_name: 'Jamie') do |u|
-
# u.is_admin = false
-
# end
-
#
-
# # Creating an Array of new objects using a block, where the block is executed for each object:
-
# User.create([{ first_name: 'Jamie' }, { first_name: 'Jeremy' }]) do |u|
-
# u.is_admin = false
-
# end
-
1
def create(attributes = nil, &block)
-
586
if attributes.is_a?(Array)
-
9
attributes.collect { |attr| create(attr, &block) }
-
else
-
583
object = new(attributes, &block)
-
583
object.save
-
583
object
-
end
-
end
-
end
-
-
# Returns true if this object hasn't been saved yet -- that is, a record
-
# for the object doesn't exist in the data store yet; otherwise, returns false.
-
1
def new_record?
-
17515
@new_record
-
end
-
-
# Returns true if this object has been destroyed, otherwise returns false.
-
1
def destroyed?
-
3942
@destroyed
-
end
-
-
# Returns true if the record is persisted, i.e. it's not a new record and it was
-
# not destroyed, otherwise returns false.
-
1
def persisted?
-
3436
!(new_record? || destroyed?)
-
end
-
-
# Saves the model.
-
#
-
# If the model is new a record gets created in the database, otherwise
-
# the existing record gets updated.
-
#
-
# By default, save always run validations. If any of them fail the action
-
# is cancelled and +save+ returns +false+. However, if you supply
-
# validate: false, validations are bypassed altogether. See
-
# ActiveRecord::Validations for more information.
-
#
-
# There's a series of callbacks associated with +save+. If any of the
-
# <tt>before_*</tt> callbacks return +false+ the action is cancelled and
-
# +save+ returns +false+. See ActiveRecord::Callbacks for further
-
# details.
-
1
def save(*)
-
1624
begin
-
1624
create_or_update
-
28
rescue ActiveRecord::RecordInvalid
-
2
false
-
end
-
end
-
-
# Saves the model.
-
#
-
# If the model is new a record gets created in the database, otherwise
-
# the existing record gets updated.
-
#
-
# With <tt>save!</tt> validations always run. If any of them fail
-
# ActiveRecord::RecordInvalid gets raised. See ActiveRecord::Validations
-
# for more information.
-
#
-
# There's a series of callbacks associated with <tt>save!</tt>. If any of
-
# the <tt>before_*</tt> callbacks return +false+ the action is cancelled
-
# and <tt>save!</tt> raises ActiveRecord::RecordNotSaved. See
-
# ActiveRecord::Callbacks for further details.
-
1
def save!(*)
-
1348
create_or_update || raise(RecordNotSaved)
-
end
-
-
# Deletes the record in the database and freezes this instance to
-
# reflect that no changes should be made (since they can't be
-
# persisted). Returns the frozen instance.
-
#
-
# The row is simply removed with an SQL +DELETE+ statement on the
-
# record's primary key, and no callbacks are executed.
-
#
-
# To enforce the object's +before_destroy+ and +after_destroy+
-
# callbacks, Observer methods, or any <tt>:dependent</tt> association
-
# options, use <tt>#destroy</tt>.
-
1
def delete
-
23
self.class.delete(id) if persisted?
-
23
@destroyed = true
-
23
freeze
-
end
-
-
# Deletes the record in the database and freezes this instance to reflect
-
# that no changes should be made (since they can't be persisted).
-
#
-
# There's a series of callbacks associated with <tt>destroy</tt>. If
-
# the <tt>before_destroy</tt> callback return +false+ the action is cancelled
-
# and <tt>destroy</tt> returns +false+. See
-
# ActiveRecord::Callbacks for further details.
-
1
def destroy
-
230
raise ReadOnlyRecord if readonly?
-
229
destroy_associations
-
229
destroy_row if persisted?
-
227
@destroyed = true
-
227
freeze
-
end
-
-
# Deletes the record in the database and freezes this instance to reflect
-
# that no changes should be made (since they can't be persisted).
-
#
-
# There's a series of callbacks associated with <tt>destroy!</tt>. If
-
# the <tt>before_destroy</tt> callback return +false+ the action is cancelled
-
# and <tt>destroy!</tt> raises ActiveRecord::RecordNotDestroyed. See
-
# ActiveRecord::Callbacks for further details.
-
1
def destroy!
-
3
destroy || raise(ActiveRecord::RecordNotDestroyed)
-
end
-
-
# Returns an instance of the specified +klass+ with the attributes of the
-
# current record. This is mostly useful in relation to single-table
-
# inheritance structures where you want a subclass to appear as the
-
# superclass. This can be used along with record identification in
-
# Action Pack to allow, say, <tt>Client < Company</tt> to do something
-
# like render <tt>partial: @client.becomes(Company)</tt> to render that
-
# instance using the companies/company partial instead of clients/client.
-
#
-
# Note: The new instance will share a link to the same attributes as the original class.
-
# So any change to the attributes in either instance will affect the other.
-
1
def becomes(klass)
-
15
became = klass.new
-
15
became.instance_variable_set("@attributes", @attributes)
-
15
became.instance_variable_set("@attributes_cache", @attributes_cache)
-
15
became.instance_variable_set("@new_record", new_record?)
-
15
became.instance_variable_set("@destroyed", destroyed?)
-
15
became.instance_variable_set("@errors", errors)
-
15
became.public_send("#{klass.inheritance_column}=", klass.name) unless self.class.descends_from_active_record?
-
15
became
-
end
-
-
# Updates a single attribute and saves the record.
-
# This is especially useful for boolean flags on existing records. Also note that
-
#
-
# * Validation is skipped.
-
# * Callbacks are invoked.
-
# * updated_at/updated_on column is updated if that column is available.
-
# * Updates all the attributes that are dirty in this object.
-
#
-
1
def update_attribute(name, value)
-
17
name = name.to_s
-
17
verify_readonly_attribute(name)
-
16
send("#{name}=", value)
-
16
save(:validate => false)
-
end
-
-
# Updates the attributes of the model from the passed-in hash and saves the
-
# record, all wrapped in a transaction. If the object is invalid, the saving
-
# will fail and false will be returned.
-
1
def update_attributes(attributes)
-
# The following transaction covers any possible database side-effects of the
-
# attributes assignment. For example, setting the IDs of a child collection.
-
79
with_transaction_returning_status do
-
79
assign_attributes(attributes)
-
79
save
-
end
-
end
-
-
# Updates its receiver just like +update_attributes+ but calls <tt>save!</tt> instead
-
# of +save+, so an exception is raised if the record is invalid.
-
1
def update_attributes!(attributes)
-
# The following transaction covers any possible database side-effects of the
-
# attributes assignment. For example, setting the IDs of a child collection.
-
12
with_transaction_returning_status do
-
12
assign_attributes(attributes)
-
12
save!
-
end
-
end
-
-
# Updates a single attribute of an object, without having to explicitly call save on that object.
-
#
-
# * Validation is skipped.
-
# * Callbacks are skipped.
-
# * updated_at/updated_on column is not updated if that column is available.
-
#
-
# Raises an +ActiveRecordError+ when called on new objects, or when the +name+
-
# attribute is marked as readonly.
-
1
def update_column(name, value)
-
12
update_columns(name => value)
-
end
-
-
# Updates the attributes from the passed-in hash, without having to explicitly call save on that object.
-
#
-
# * Validation is skipped.
-
# * Callbacks are skipped.
-
# * updated_at/updated_on column is not updated if that column is available.
-
#
-
# Raises an +ActiveRecordError+ when called on new objects, or when at least
-
# one of the attributes is marked as readonly.
-
1
def update_columns(attributes)
-
82
raise ActiveRecordError, "can not update on a new record object" unless persisted?
-
-
80
attributes.each_key do |key|
-
84
verify_readonly_attribute(key.to_s)
-
end
-
-
78
updated_count = self.class.where(self.class.primary_key => id).update_all(attributes)
-
-
78
attributes.each do |k,v|
-
81
raw_write_attribute(k,v)
-
end
-
-
78
updated_count == 1
-
end
-
-
# Initializes +attribute+ to zero if +nil+ and adds the value passed as +by+ (default is 1).
-
# The increment is performed directly on the underlying attribute, no setter is invoked.
-
# Only makes sense for number-based attributes. Returns +self+.
-
1
def increment(attribute, by = 1)
-
7
self[attribute] ||= 0
-
7
self[attribute] += by
-
7
self
-
end
-
-
# Wrapper around +increment+ that saves the record. This method differs from
-
# its non-bang version in that it passes through the attribute setter.
-
# Saving is not subjected to validation checks. Returns +true+ if the
-
# record could be saved.
-
1
def increment!(attribute, by = 1)
-
5
increment(attribute, by).update_attribute(attribute, self[attribute])
-
end
-
-
# Initializes +attribute+ to zero if +nil+ and subtracts the value passed as +by+ (default is 1).
-
# The decrement is performed directly on the underlying attribute, no setter is invoked.
-
# Only makes sense for number-based attributes. Returns +self+.
-
1
def decrement(attribute, by = 1)
-
6
self[attribute] ||= 0
-
6
self[attribute] -= by
-
6
self
-
end
-
-
# Wrapper around +decrement+ that saves the record. This method differs from
-
# its non-bang version in that it passes through the attribute setter.
-
# Saving is not subjected to validation checks. Returns +true+ if the
-
# record could be saved.
-
1
def decrement!(attribute, by = 1)
-
4
decrement(attribute, by).update_attribute(attribute, self[attribute])
-
end
-
-
# Assigns to +attribute+ the boolean opposite of <tt>attribute?</tt>. So
-
# if the predicate returns +true+ the attribute will become +false+. This
-
# method toggles directly the underlying value without calling any setter.
-
# Returns +self+.
-
1
def toggle(attribute)
-
2
self[attribute] = !send("#{attribute}?")
-
2
self
-
end
-
-
# Wrapper around +toggle+ that saves the record. This method differs from
-
# its non-bang version in that it passes through the attribute setter.
-
# Saving is not subjected to validation checks. Returns +true+ if the
-
# record could be saved.
-
1
def toggle!(attribute)
-
1
toggle(attribute).update_attribute(attribute, self[attribute])
-
end
-
-
# Reloads the attributes of this object from the database.
-
# The optional options argument is passed to find when reloading so you
-
# may do e.g. record.reload(lock: true) to reload the same record with
-
# an exclusive row lock.
-
1
def reload(options = nil)
-
447
clear_aggregation_cache
-
447
clear_association_cache
-
-
447
fresh_object =
-
if options && options[:lock]
-
10
self.class.unscoped { self.class.lock.find(id) }
-
else
-
884
self.class.unscoped { self.class.find(id) }
-
end
-
-
442
@attributes.update(fresh_object.instance_variable_get('@attributes'))
-
442
@columns_hash = fresh_object.instance_variable_get('@columns_hash')
-
-
442
@attributes_cache = {}
-
442
self
-
end
-
-
# Saves the record with the updated_at/on attributes set to the current time.
-
# Please note that no validation is performed and no callbacks are executed.
-
# If an attribute name is passed, that attribute is updated along with
-
# updated_at/on attributes.
-
#
-
# product.touch # updates updated_at/on
-
# product.touch(:designed_at) # updates the designed_at attribute and updated_at/on
-
#
-
# If used along with +belongs_to+ then +touch+ will invoke +touch+ method on associated object.
-
#
-
# class Brake < ActiveRecord::Base
-
# belongs_to :car, touch: true
-
# end
-
#
-
# class Car < ActiveRecord::Base
-
# belongs_to :corporation, touch: true
-
# end
-
#
-
# # triggers @brake.car.touch and @brake.car.corporation.touch
-
# @brake.touch
-
1
def touch(name = nil)
-
28
attributes = timestamp_attributes_for_update_in_model
-
28
attributes << name if name
-
-
28
unless attributes.empty?
-
27
current_time = current_time_from_proper_timezone
-
27
changes = {}
-
-
27
attributes.each do |column|
-
29
column = column.to_s
-
29
changes[column] = write_attribute(column, current_time)
-
end
-
-
27
changes[self.class.locking_column] = increment_lock if locking_enabled?
-
-
27
@changed_attributes.except!(*changes.keys)
-
27
primary_key = self.class.primary_key
-
27
self.class.unscoped.where(primary_key => self[primary_key]).update_all(changes) == 1
-
end
-
end
-
-
1
private
-
-
# A hook to be overridden by association modules.
-
1
def destroy_associations
-
end
-
-
1
def destroy_row
-
228
relation_for_destroy.delete_all
-
end
-
-
1
def relation_for_destroy
-
228
pk = self.class.primary_key
-
228
column = self.class.columns_hash[pk]
-
228
substitute = connection.substitute_at(column, 0)
-
-
228
relation = self.class.unscoped.where(
-
self.class.arel_table[pk].eq(substitute))
-
-
228
relation.bind_values = [[column, id]]
-
228
relation
-
end
-
-
1
def create_or_update
-
2951
raise ReadOnlyRecord if readonly?
-
2935
result = new_record? ? create : update
-
2908
result != false
-
end
-
-
# Updates the associated record with values matching those of the instance attributes.
-
# Returns the number of affected rows.
-
1
def update(attribute_names = @attributes.keys)
-
586
attributes_with_values = arel_attributes_with_values_for_update(attribute_names)
-
586
return 0 if attributes_with_values.empty?
-
343
klass = self.class
-
343
stmt = klass.unscoped.where(klass.arel_table[klass.primary_key].eq(id)).arel.compile_update(attributes_with_values)
-
343
klass.connection.update stmt
-
end
-
-
# Creates a record with values matching those of the instance attributes
-
# and returns its id.
-
1
def create(attribute_names = @attributes.keys)
-
2321
attributes_values = arel_attributes_with_values_for_create(attribute_names)
-
-
2320
new_id = self.class.unscoped.insert attributes_values
-
2320
self.id ||= new_id if self.class.primary_key
-
-
2320
@new_record = false
-
2320
id
-
end
-
-
1
def verify_readonly_attribute(name)
-
101
raise ActiveRecordError, "#{name} is marked as readonly" if self.class.readonly_attributes.include?(name)
-
end
-
end
-
end
-
-
1
module ActiveRecord
-
# = Active Record Query Cache
-
1
class QueryCache
-
1
module ClassMethods
-
# Enable the query cache within the block if Active Record is configured.
-
1
def cache(&block)
-
20
if ActiveRecord::Base.connected?
-
20
connection.cache(&block)
-
else
-
yield
-
end
-
end
-
-
# Disable the query cache within the block if Active Record is configured.
-
1
def uncached(&block)
-
105
if ActiveRecord::Base.connected?
-
105
connection.uncached(&block)
-
else
-
yield
-
end
-
end
-
end
-
-
1
def initialize(app)
-
9
@app = app
-
end
-
-
1
def call(env)
-
9
enabled = ActiveRecord::Base.connection.query_cache_enabled
-
9
connection_id = ActiveRecord::Base.connection_id
-
9
ActiveRecord::Base.connection.enable_query_cache!
-
-
9
response = @app.call(env)
-
6
response[2] = Rack::BodyProxy.new(response[2]) do
-
3
restore_query_cache_settings(connection_id, enabled)
-
end
-
-
6
response
-
rescue Exception => e
-
3
restore_query_cache_settings(connection_id, enabled)
-
3
raise e
-
end
-
-
1
private
-
-
1
def restore_query_cache_settings(connection_id, enabled)
-
6
ActiveRecord::Base.connection_id = connection_id
-
6
ActiveRecord::Base.connection.clear_query_cache
-
6
ActiveRecord::Base.connection.disable_query_cache! unless enabled
-
end
-
-
end
-
end
-
-
1
module ActiveRecord
-
1
module Querying
-
1
delegate :find, :take, :take!, :first, :first!, :last, :last!, :exists?, :any?, :many?, :to => :all
-
1
delegate :first_or_create, :first_or_create!, :first_or_initialize, :to => :all
-
1
delegate :find_or_create_by, :find_or_create_by!, :find_or_initialize_by, :to => :all
-
1
delegate :find_by, :find_by!, :to => :all
-
1
delegate :destroy, :destroy_all, :delete, :delete_all, :update, :update_all, :to => :all
-
1
delegate :find_each, :find_in_batches, :to => :all
-
1
delegate :select, :group, :order, :except, :reorder, :limit, :offset, :joins,
-
:where, :preload, :eager_load, :includes, :from, :lock, :readonly,
-
:having, :create_with, :uniq, :references, :none, :to => :all
-
1
delegate :count, :average, :minimum, :maximum, :sum, :calculate, :pluck, :ids, :to => :all
-
-
# Executes a custom SQL query against your database and returns all the results. The results will
-
# be returned as an array with columns requested encapsulated as attributes of the model you call
-
# this method from. If you call <tt>Product.find_by_sql</tt> then the results will be returned in
-
# a Product object with the attributes you specified in the SQL query.
-
#
-
# If you call a complicated SQL query which spans multiple tables the columns specified by the
-
# SELECT will be attributes of the model, whether or not they are columns of the corresponding
-
# table.
-
#
-
# The +sql+ parameter is a full SQL query as a string. It will be called as is, there will be
-
# no database agnostic conversions performed. This should be a last resort because using, for example,
-
# MySQL specific terms will lock you to using that particular database engine or require you to
-
# change your call if you switch engines.
-
#
-
# ==== Examples
-
# # A simple SQL query spanning multiple tables
-
# Post.find_by_sql "SELECT p.title, c.author FROM posts p, comments c WHERE p.id = c.post_id"
-
# > [#<Post:0x36bff9c @attributes={"title"=>"Ruby Meetup", "first_name"=>"Quentin"}>, ...]
-
#
-
# # You can use the same string replacement techniques as you can with ActiveRecord#find
-
# Post.find_by_sql ["SELECT title FROM posts WHERE author = ? AND created > ?", author_id, start_date]
-
# > [#<Post:0x36bff9c @attributes={"title"=>"The Cheap Man Buys Twice"}>, ...]
-
1
def find_by_sql(sql, binds = [])
-
6886
logging_query_plan do
-
6886
result_set = connection.select_all(sanitize_sql(sql), "#{name} Load", binds)
-
6879
column_types = {}
-
-
6879
if result_set.respond_to? :column_types
-
6879
column_types = result_set.column_types
-
else
-
ActiveSupport::Deprecation.warn "the object returned from `select_all` must respond to `column_types`"
-
end
-
-
16871
result_set.map { |record| instantiate(record, column_types) }
-
end
-
end
-
-
# Returns the result of an SQL statement that should only include a COUNT(*) in the SELECT part.
-
# The use of this method should be restricted to complicated SQL queries that can't be executed
-
# using the ActiveRecord::Calculations class methods. Look into those before using this.
-
#
-
# ==== Parameters
-
#
-
# * +sql+ - An SQL statement which should return a count query from the database, see the example below.
-
#
-
# ==== Examples
-
#
-
# Product.count_by_sql "SELECT COUNT(*) FROM sales s, customers c WHERE s.customer_id = c.id"
-
1
def count_by_sql(sql)
-
33
logging_query_plan do
-
33
sql = sanitize_conditions(sql)
-
33
connection.select_value(sql, "#{name} Count").to_i
-
end
-
end
-
end
-
end
-
-
1
module ActiveRecord
-
1
module ReadonlyAttributes
-
1
extend ActiveSupport::Concern
-
-
1
included do
-
1
class_attribute :_attr_readonly, instance_accessor: false
-
1
self._attr_readonly = []
-
end
-
-
1
module ClassMethods
-
# Attributes listed as readonly will be used to create a new record but update operations will
-
# ignore these fields.
-
1
def attr_readonly(*attributes)
-
30
self._attr_readonly = Set.new(attributes.map { |a| a.to_s }) + (self._attr_readonly || [])
-
end
-
-
# Returns an array of all the attributes that have been specified as readonly.
-
1
def readonly_attributes
-
876
self._attr_readonly
-
end
-
end
-
-
1
def _attr_readonly
-
1
message = "Instance level _attr_readonly method is deprecated, please use class level method."
-
1
ActiveSupport::Deprecation.warn message
-
1
defined?(@_attr_readonly) ? @_attr_readonly : self.class._attr_readonly
-
end
-
end
-
end
-
-
1
module ActiveRecord
-
# = Active Record Reflection
-
1
module Reflection # :nodoc:
-
1
extend ActiveSupport::Concern
-
-
1
included do
-
2
class_attribute :reflections
-
2
self.reflections = {}
-
end
-
-
# Reflection enables to interrogate Active Record classes and objects
-
# about their associations and aggregations. This information can,
-
# for example, be used in a form builder that takes an Active Record object
-
# and creates input fields for all of the attributes depending on their type
-
# and displays the associations to other objects.
-
#
-
# MacroReflection class has info for AggregateReflection and AssociationReflection
-
# classes.
-
1
module ClassMethods
-
1
def create_reflection(macro, name, scope, options, active_record)
-
623
case macro
-
when :has_many, :belongs_to, :has_one, :has_and_belongs_to_many
-
615
klass = options[:through] ? ThroughReflection : AssociationReflection
-
615
reflection = klass.new(macro, name, scope, options, active_record)
-
when :composed_of
-
8
reflection = AggregateReflection.new(macro, name, scope, options, active_record)
-
end
-
-
623
self.reflections = self.reflections.merge(name => reflection)
-
623
reflection
-
end
-
-
# Returns an array of AggregateReflection objects for all the aggregations in the class.
-
1
def reflect_on_all_aggregations
-
3
reflections.values.grep(AggregateReflection)
-
end
-
-
# Returns the AggregateReflection object for the named +aggregation+ (use the symbol).
-
#
-
# Account.reflect_on_aggregation(:balance) # => the balance AggregateReflection
-
#
-
1
def reflect_on_aggregation(aggregation)
-
1399
reflection = reflections[aggregation]
-
1399
reflection if reflection.is_a?(AggregateReflection)
-
end
-
-
# Returns an array of AssociationReflection objects for all the
-
# associations in the class. If you only want to reflect on a certain
-
# association type, pass in the symbol (<tt>:has_many</tt>, <tt>:has_one</tt>,
-
# <tt>:belongs_to</tt>) as the first parameter.
-
#
-
# Example:
-
#
-
# Account.reflect_on_all_associations # returns an array of all associations
-
# Account.reflect_on_all_associations(:has_many) # returns an array of all has_many associations
-
#
-
1
def reflect_on_all_associations(macro = nil)
-
4126
association_reflections = reflections.values.grep(AssociationReflection)
-
4661
macro ? association_reflections.select { |reflection| reflection.macro == macro } : association_reflections
-
end
-
-
# Returns the AssociationReflection object for the +association+ (use the symbol).
-
#
-
# Account.reflect_on_association(:owner) # returns the owner AssociationReflection
-
# Invoice.reflect_on_association(:line_items).macro # returns :has_many
-
#
-
1
def reflect_on_association(association)
-
6731
reflection = reflections[association]
-
6731
reflection if reflection.is_a?(AssociationReflection)
-
end
-
-
# Returns an array of AssociationReflection objects for all associations which have <tt>:autosave</tt> enabled.
-
1
def reflect_on_all_autosave_associations
-
581
reflections.values.select { |reflection| reflection.options[:autosave] }
-
end
-
end
-
-
# Abstract base class for AggregateReflection and AssociationReflection. Objects of
-
# AggregateReflection and AssociationReflection are returned by the Reflection::ClassMethods.
-
1
class MacroReflection
-
# Returns the name of the macro.
-
#
-
# <tt>composed_of :balance, class_name: 'Money'</tt> returns <tt>:balance</tt>
-
# <tt>has_many :clients</tt> returns <tt>:clients</tt>
-
1
attr_reader :name
-
-
# Returns the macro type.
-
#
-
# <tt>composed_of :balance, class_name: 'Money'</tt> returns <tt>:composed_of</tt>
-
# <tt>has_many :clients</tt> returns <tt>:has_many</tt>
-
1
attr_reader :macro
-
-
1
attr_reader :scope
-
-
# Returns the hash of options used for the macro.
-
#
-
# <tt>composed_of :balance, class_name: 'Money'</tt> returns <tt>{ class_name: "Money" }</tt>
-
# <tt>has_many :clients</tt> returns +{}+
-
1
attr_reader :options
-
-
1
attr_reader :active_record
-
-
1
attr_reader :plural_name # :nodoc:
-
-
1
def initialize(macro, name, scope, options, active_record)
-
656
@macro = macro
-
656
@name = name
-
656
@scope = scope
-
656
@options = options
-
656
@active_record = active_record
-
656
@plural_name = active_record.pluralize_table_names ?
-
name.to_s.pluralize : name.to_s
-
end
-
-
# Returns the class for the macro.
-
#
-
# <tt>composed_of :balance, class_name: 'Money'</tt> returns the Money class
-
# <tt>has_many :clients</tt> returns the Client class
-
1
def klass
-
8
@klass ||= class_name.constantize
-
end
-
-
# Returns the class name for the macro.
-
#
-
# <tt>composed_of :balance, class_name: 'Money'</tt> returns <tt>'Money'</tt>
-
# <tt>has_many :clients</tt> returns <tt>'Client'</tt>
-
1
def class_name
-
691
@class_name ||= (options[:class_name] || derive_class_name).to_s
-
end
-
-
# Returns +true+ if +self+ and +other_aggregation+ have the same +name+ attribute, +active_record+ attribute,
-
# and +other_aggregation+ has an options hash assigned to it.
-
1
def ==(other_aggregation)
-
super ||
-
other_aggregation.kind_of?(self.class) &&
-
name == other_aggregation.name &&
-
other_aggregation.options &&
-
11699
active_record == other_aggregation.active_record
-
end
-
-
1
private
-
1
def derive_class_name
-
1
name.to_s.camelize
-
end
-
end
-
-
-
# Holds all the meta-data about an aggregation as it was specified in the
-
# Active Record class.
-
1
class AggregateReflection < MacroReflection #:nodoc:
-
1
def mapping
-
32
mapping = options[:mapping] || [name, name]
-
32
mapping.first.is_a?(Array) ? mapping : [mapping]
-
end
-
end
-
-
# Holds all the meta-data about an association as it was specified in the
-
# Active Record class.
-
1
class AssociationReflection < MacroReflection #:nodoc:
-
# Returns the target association's class.
-
#
-
# class Author < ActiveRecord::Base
-
# has_many :books
-
# end
-
#
-
# Author.reflect_on_association(:books).klass
-
# # => Book
-
#
-
# <b>Note:</b> Do not call +klass.new+ or +klass.create+ to instantiate
-
# a new association object. Use +build_association+ or +create_association+
-
# instead. This allows plugins to hook into association object creation.
-
1
def klass
-
40562
@klass ||= active_record.send(:compute_type, class_name)
-
end
-
-
1
def initialize(*args)
-
644
super
-
644
@collection = [:has_many, :has_and_belongs_to_many].include?(macro)
-
end
-
-
# Returns a new, unsaved instance of the associated class. +options+ will
-
# be passed to the class's constructor.
-
1
def build_association(attributes, &block)
-
793
klass.new(attributes, &block)
-
end
-
-
1
def table_name
-
1268
@table_name ||= klass.table_name
-
end
-
-
1
def quoted_table_name
-
17
@quoted_table_name ||= klass.quoted_table_name
-
end
-
-
1
def join_table
-
1273
@join_table ||= options[:join_table] || derive_join_table
-
end
-
-
1
def foreign_key
-
14705
@foreign_key ||= options[:foreign_key] || derive_foreign_key
-
end
-
-
1
def foreign_type
-
1222
@foreign_type ||= options[:foreign_type] || "#{name}_type"
-
end
-
-
1
def type
-
4594
@type ||= options[:as] && "#{options[:as]}_type"
-
end
-
-
1
def primary_key_column
-
40
@primary_key_column ||= klass.columns.find { |c| c.name == klass.primary_key }
-
end
-
-
1
def association_foreign_key
-
1501
@association_foreign_key ||= options[:association_foreign_key] || class_name.foreign_key
-
end
-
-
# klass option is necessary to support loading polymorphic associations
-
1
def association_primary_key(klass = nil)
-
1646
options[:primary_key] || primary_key(klass || self.klass)
-
end
-
-
1
def active_record_primary_key
-
4379
@active_record_primary_key ||= options[:primary_key] || primary_key(active_record)
-
end
-
-
1
def counter_cache_column
-
501
if options[:counter_cache] == true
-
53
"#{active_record.name.demodulize.underscore.pluralize}_count"
-
448
elsif options[:counter_cache]
-
21
options[:counter_cache].to_s
-
end
-
end
-
-
1
def columns(tbl_name)
-
@columns ||= klass.connection.columns(tbl_name)
-
end
-
-
1
def reset_column_information
-
@columns = nil
-
end
-
-
1
def check_validity!
-
4421
check_validity_of_inverse!
-
-
4418
if has_and_belongs_to_many? && association_foreign_key == foreign_key
-
1
raise HasAndBelongsToManyAssociationForeignKeyNeeded.new(self)
-
end
-
end
-
-
1
def check_validity_of_inverse!
-
5050
unless options[:polymorphic]
-
4763
if has_inverse? && inverse_of.nil?
-
3
raise InverseOfAssociationNotFoundError.new(self)
-
end
-
end
-
end
-
-
1
def through_reflection
-
nil
-
end
-
-
1
def source_reflection
-
nil
-
end
-
-
# A chain of reflections from this one back to the owner. For more see the explanation in
-
# ThroughReflection.
-
1
def chain
-
8236
[self]
-
end
-
-
1
def nested?
-
107
false
-
end
-
-
# An array of arrays of scopes. Each item in the outside array corresponds to a reflection
-
# in the #chain.
-
1
def scope_chain
-
2940
scope ? [[scope]] : [[]]
-
end
-
-
1
alias :source_macro :macro
-
-
1
def has_inverse?
-
8787
@options[:inverse_of]
-
end
-
-
1
def inverse_of
-
3726
if has_inverse?
-
357
@inverse_of ||= klass.reflect_on_association(options[:inverse_of])
-
end
-
end
-
-
1
def polymorphic_inverse_of(associated_class)
-
292
if has_inverse?
-
19
if inverse_relationship = associated_class.reflect_on_association(options[:inverse_of])
-
17
inverse_relationship
-
else
-
2
raise InverseOfAssociationNotFoundError.new(self, associated_class)
-
end
-
end
-
end
-
-
# Returns whether or not this association reflection is for a collection
-
# association. Returns +true+ if the +macro+ is either +has_many+ or
-
# +has_and_belongs_to_many+, +false+ otherwise.
-
1
def collection?
-
1605
@collection
-
end
-
-
# Returns whether or not the association should be validated as part of
-
# the parent's validation.
-
#
-
# Unless you explicitly disable validation with
-
# <tt>validate: false</tt>, validation will take place when:
-
#
-
# * you explicitly enable validation; <tt>validate: true</tt>
-
# * you use autosave; <tt>autosave: true</tt>
-
# * the association is a +has_many+ association
-
1
def validate?
-
724
!options[:validate].nil? ? options[:validate] : (options[:autosave] == true || macro == :has_many)
-
end
-
-
# Returns +true+ if +self+ is a +belongs_to+ reflection.
-
1
def belongs_to?
-
261
macro == :belongs_to
-
end
-
-
1
def has_and_belongs_to_many?
-
4418
macro == :has_and_belongs_to_many
-
end
-
-
1
def association_class
-
4494
case macro
-
when :belongs_to
-
1292
if options[:polymorphic]
-
286
Associations::BelongsToPolymorphicAssociation
-
else
-
1006
Associations::BelongsToAssociation
-
end
-
when :has_and_belongs_to_many
-
698
Associations::HasAndBelongsToManyAssociation
-
when :has_many
-
1916
if options[:through]
-
451
Associations::HasManyThroughAssociation
-
else
-
1465
Associations::HasManyAssociation
-
end
-
when :has_one
-
588
if options[:through]
-
75
Associations::HasOneThroughAssociation
-
else
-
513
Associations::HasOneAssociation
-
end
-
end
-
end
-
-
1
def polymorphic?
-
6
options.key? :polymorphic
-
end
-
-
1
private
-
1
def derive_class_name
-
174
class_name = name.to_s.camelize
-
174
class_name = class_name.singularize if collection?
-
174
class_name
-
end
-
-
1
def derive_foreign_key
-
261
if belongs_to?
-
75
"#{name}_id"
-
186
elsif options[:as]
-
23
"#{options[:as]}_id"
-
else
-
163
active_record.name.foreign_key
-
end
-
end
-
-
1
def derive_join_table
-
37
[active_record.table_name, klass.table_name].sort.join("\0").gsub(/^(.*_)(.+)\0\1(.+)/, '\1\2_\3').gsub("\0", "_")
-
end
-
-
1
def primary_key(klass)
-
2290
klass.primary_key || raise(UnknownPrimaryKey.new(klass))
-
end
-
end
-
-
# Holds all the meta-data about a :through association as it was specified
-
# in the Active Record class.
-
1
class ThroughReflection < AssociationReflection #:nodoc:
-
1
delegate :foreign_key, :foreign_type, :association_foreign_key,
-
:active_record_primary_key, :type, :to => :source_reflection
-
-
# Gets the source of the through reflection. It checks both a singularized
-
# and pluralized form for <tt>:belongs_to</tt> or <tt>:has_many</tt>.
-
#
-
# class Post < ActiveRecord::Base
-
# has_many :taggings
-
# has_many :tags, through: :taggings
-
# end
-
#
-
1
def source_reflection
-
6554
@source_reflection ||= source_reflection_names.collect { |name| through_reflection.klass.reflect_on_association(name) }.compact.first
-
end
-
-
# Returns the AssociationReflection object specified in the <tt>:through</tt> option
-
# of a HasManyThrough or HasOneThrough association.
-
#
-
# class Post < ActiveRecord::Base
-
# has_many :taggings
-
# has_many :tags, through: :taggings
-
# end
-
#
-
# tags_reflection = Post.reflect_on_association(:tags)
-
# taggings_reflection = tags_reflection.through_reflection
-
#
-
1
def through_reflection
-
3678
@through_reflection ||= active_record.reflect_on_association(options[:through])
-
end
-
-
# Returns an array of reflections which are involved in this association. Each item in the
-
# array corresponds to a table which will be part of the query for this association.
-
#
-
# The chain is built by recursively calling #chain on the source reflection and the through
-
# reflection. The base case for the recursion is a normal association, which just returns
-
# [self] as its #chain.
-
1
def chain
-
@chain ||= begin
-
119
chain = source_reflection.chain + through_reflection.chain
-
119
chain[0] = self # Use self so we don't lose the information from :source_type
-
119
chain
-
3271
end
-
end
-
-
# Consider the following example:
-
#
-
# class Person
-
# has_many :articles
-
# has_many :comment_tags, through: :articles
-
# end
-
#
-
# class Article
-
# has_many :comments
-
# has_many :comment_tags, through: :comments, source: :tags
-
# end
-
#
-
# class Comment
-
# has_many :tags
-
# end
-
#
-
# There may be scopes on Person.comment_tags, Article.comment_tags and/or Comment.tags,
-
# but only Comment.tags will be represented in the #chain. So this method creates an array
-
# of scopes corresponding to the chain.
-
1
def scope_chain
-
@scope_chain ||= begin
-
119
scope_chain = source_reflection.scope_chain.map(&:dup)
-
-
# Add to it the scope from this reflection (if any)
-
119
scope_chain.first << scope if scope
-
-
119
through_scope_chain = through_reflection.scope_chain
-
-
119
if options[:source_type]
-
through_scope_chain.first <<
-
2
through_reflection.klass.where(foreign_type => options[:source_type])
-
end
-
-
# Recursively fill out the rest of the array from the through reflection
-
119
scope_chain + through_scope_chain
-
1086
end
-
end
-
-
# The macro used by the source association
-
1
def source_macro
-
1879
source_reflection.source_macro
-
end
-
-
# A through association is nested if there would be more than one join table
-
1
def nested?
-
208
chain.length > 2 || through_reflection.macro == :has_and_belongs_to_many
-
end
-
-
# We want to use the klass from this reflection, rather than just delegate straight to
-
# the source_reflection, because the source_reflection may be polymorphic. We still
-
# need to respect the source_reflection's :primary_key option, though.
-
1
def association_primary_key(klass = nil)
-
# Get the "actual" source reflection if the immediate source reflection has a
-
# source reflection itself
-
462
source_reflection = self.source_reflection
-
462
while source_reflection.source_reflection
-
50
source_reflection = source_reflection.source_reflection
-
end
-
-
462
source_reflection.options[:primary_key] || primary_key(klass || self.klass)
-
end
-
-
# Gets an array of possible <tt>:through</tt> source reflection names:
-
#
-
# [:singularized, :pluralized]
-
#
-
1
def source_reflection_names
-
288
@source_reflection_names ||= (options[:source] ? [options[:source]] : [name.to_s.singularize, name]).collect { |n| n.to_sym }
-
end
-
-
1
def source_options
-
source_reflection.options
-
end
-
-
1
def through_options
-
through_reflection.options
-
end
-
-
1
def check_validity!
-
633
if through_reflection.nil?
-
1
raise HasManyThroughAssociationNotFoundError.new(active_record.name, self)
-
end
-
-
632
if through_reflection.options[:polymorphic]
-
1
raise HasManyThroughAssociationPolymorphicThroughError.new(active_record.name, self)
-
end
-
-
631
if source_reflection.nil?
-
raise HasManyThroughSourceAssociationNotFoundError.new(self)
-
end
-
-
631
if options[:source_type] && source_reflection.options[:polymorphic].nil?
-
raise HasManyThroughAssociationPointlessSourceTypeError.new(active_record.name, self, source_reflection)
-
end
-
-
631
if source_reflection.options[:polymorphic] && options[:source_type].nil?
-
1
raise HasManyThroughAssociationPolymorphicSourceError.new(active_record.name, self, source_reflection)
-
end
-
-
630
if macro == :has_one && through_reflection.collection?
-
1
raise HasOneThroughCantAssociateThroughCollection.new(active_record.name, self, through_reflection)
-
end
-
-
629
check_validity_of_inverse!
-
end
-
-
1
private
-
1
def derive_class_name
-
# get the class_name of the belongs_to association of the through reflection
-
119
options[:source_type] || source_reflection.class_name
-
end
-
end
-
end
-
end
-
# -*- coding: utf-8 -*-
-
-
1
module ActiveRecord
-
# = Active Record Relation
-
1
class Relation
-
1
JoinOperation = Struct.new(:relation, :join_class, :on)
-
-
1
MULTI_VALUE_METHODS = [:includes, :eager_load, :preload, :select, :group,
-
:order, :joins, :where, :having, :bind, :references,
-
:extending]
-
-
1
SINGLE_VALUE_METHODS = [:limit, :offset, :lock, :readonly, :from, :reordering,
-
:reverse_order, :uniq, :create_with]
-
-
1
VALUE_METHODS = MULTI_VALUE_METHODS + SINGLE_VALUE_METHODS
-
-
1
include FinderMethods, Calculations, SpawnMethods, QueryMethods, Batches, Explain, Delegation
-
-
1
attr_reader :table, :klass, :loaded
-
1
attr_accessor :default_scoped
-
1
alias :model :klass
-
1
alias :loaded? :loaded
-
1
alias :default_scoped? :default_scoped
-
-
1
def initialize(klass, table, values = {})
-
28351
@klass = klass
-
28351
@table = table
-
28351
@values = values
-
28351
@implicit_readonly = nil
-
28351
@loaded = false
-
28351
@default_scoped = false
-
end
-
-
1
def insert(values)
-
2320
primary_key_value = nil
-
-
2320
if primary_key && Hash === values
-
2264
primary_key_value = values[values.keys.find { |k|
-
5582
k.name == primary_key
-
}]
-
-
2264
if !primary_key_value && connection.prefetch_primary_key?(klass.table_name)
-
primary_key_value = connection.next_sequence_value(klass.sequence_name)
-
values[klass.arel_table[klass.primary_key]] = primary_key_value
-
end
-
end
-
-
2320
im = arel.create_insert
-
2320
im.into @table
-
-
2320
conn = @klass.connection
-
-
7977
substitutes = values.sort_by { |arel_attr,_| arel_attr.name }
-
2320
binds = substitutes.map do |arel_attr, value|
-
5657
[@klass.columns_hash[arel_attr.name], value]
-
end
-
-
2320
substitutes.each_with_index do |tuple, i|
-
5657
tuple[1] = conn.substitute_at(binds[i][0], i)
-
end
-
-
2320
if values.empty? # empty insert
-
298
im.values = Arel.sql(connection.empty_insert_statement_value)
-
else
-
2022
im.insert substitutes
-
end
-
-
2320
conn.insert(
-
im,
-
'SQL',
-
primary_key,
-
primary_key_value,
-
nil,
-
binds)
-
end
-
-
# Initializes new record from relation while maintaining the current
-
# scope.
-
#
-
# Expects arguments in the same format as +Base.new+.
-
#
-
# users = User.where(name: 'DHH')
-
# user = users.new # => #<User id: nil, name: "DHH", created_at: nil, updated_at: nil>
-
#
-
# You can also pass a block to new with the new record as argument:
-
#
-
# user = users.new { |user| user.name = 'Oscar' }
-
# user.name # => Oscar
-
1
def new(*args, &block)
-
88
scoping { @klass.new(*args, &block) }
-
end
-
-
1
def initialize_copy(other)
-
# This method is a hot spot, so for now, use Hash[] to dup the hash.
-
# https://bugs.ruby-lang.org/issues/7166
-
34889
@values = Hash[@values]
-
34889
@values[:bind] = @values[:bind].dup if @values.key? :bind
-
34889
reset
-
end
-
-
1
alias build new
-
-
# Tries to create a new record with the same scoped attributes
-
# defined in the relation. Returns the initialized object if validation fails.
-
#
-
# Expects arguments in the same format as +Base.create+.
-
#
-
# ==== Examples
-
# users = User.where(name: 'Oscar')
-
# users.create # #<User id: 3, name: "oscar", ...>
-
#
-
# users.create(name: 'fxn')
-
# users.create # #<User id: 4, name: "fxn", ...>
-
#
-
# users.create { |user| user.name = 'tenderlove' }
-
# # #<User id: 5, name: "tenderlove", ...>
-
#
-
# users.create(name: nil) # validation on name
-
# # #<User id: nil, name: nil, ...>
-
1
def create(*args, &block)
-
56
scoping { @klass.create(*args, &block) }
-
end
-
-
# Similar to #create, but calls +create!+ on the base class. Raises
-
# an exception if a validation error occurs.
-
#
-
# Expects arguments in the same format as <tt>Base.create!</tt>.
-
1
def create!(*args, &block)
-
40
scoping { @klass.create!(*args, &block) }
-
end
-
-
1
def first_or_create(attributes = nil, &block) # :nodoc:
-
10
first || create(attributes, &block)
-
end
-
-
1
def first_or_create!(attributes = nil, &block) # :nodoc:
-
13
first || create!(attributes, &block)
-
end
-
-
1
def first_or_initialize(attributes = nil, &block) # :nodoc:
-
5
first || new(attributes, &block)
-
end
-
-
# Finds the first record with the given attributes, or creates a record with the attributes
-
# if one is not found.
-
#
-
# ==== Examples
-
# # Find the first user named Penélope or create a new one.
-
# User.find_or_create_by(first_name: 'Penélope')
-
# # => <User id: 1, first_name: 'Penélope', last_name: nil>
-
#
-
# # Find the first user named Penélope or create a new one.
-
# # We already have one so the existing record will be returned.
-
# User.find_or_create_by(first_name: 'Penélope')
-
# # => <User id: 1, first_name: 'Penélope', last_name: nil>
-
#
-
# # Find the first user named Scarlett or create a new one with a particular last name.
-
# User.create_with(last_name: 'Johansson').find_or_create_by(first_name: 'Scarlett')
-
# # => <User id: 2, first_name: 'Scarlett', last_name: 'Johansson'>
-
#
-
# # Find the first user named Scarlett or create a new one with a different last name.
-
# # We already have one so the existing record will be returned.
-
# User.find_or_create_by(first_name: 'Scarlett') do |user|
-
# user.last_name = "O'Hara"
-
# end
-
# # => <User id: 2, first_name: 'Scarlett', last_name: 'Johansson'>
-
1
def find_or_create_by(attributes, &block)
-
4
find_by(attributes) || create(attributes, &block)
-
end
-
-
# Like <tt>find_or_create_by</tt>, but calls <tt>create!</tt> so an exception is raised if the created record is invalid.
-
1
def find_or_create_by!(attributes, &block)
-
1
find_by(attributes) || create!(attributes, &block)
-
end
-
-
# Like <tt>find_or_create_by</tt>, but calls <tt>new</tt> instead of <tt>create</tt>.
-
1
def find_or_initialize_by(attributes, &block)
-
2
find_by(attributes) || new(attributes, &block)
-
end
-
-
# Runs EXPLAIN on the query or queries triggered by this relation and
-
# returns the result as a string. The string is formatted imitating the
-
# ones printed by the database shell.
-
#
-
# Note that this method actually runs the queries, since the results of some
-
# are needed by the next ones when eager loading is going on.
-
#
-
# Please see further details in the
-
# {Active Record Query Interface guide}[http://guides.rubyonrails.org/active_record_querying.html#running-explain].
-
1
def explain
-
4
_, queries = collecting_queries_for_explain { exec_queries }
-
2
exec_explain(queries)
-
end
-
-
# Converts relation objects to Array.
-
1
def to_a
-
7060
load
-
7044
@records
-
end
-
-
1
def as_json(options = nil) #:nodoc:
-
2
to_a.as_json(options)
-
end
-
-
# Returns size of the records.
-
1
def size
-
37
loaded? ? @records.length : count
-
end
-
-
# Returns true if there are no records.
-
1
def empty?
-
43
return @records.empty? if loaded?
-
-
39
c = count
-
39
c.respond_to?(:zero?) ? c.zero? : c.empty?
-
end
-
-
# Returns true if there are any records.
-
1
def any?
-
11
if block_given?
-
16
to_a.any? { |*block_args| yield(*block_args) }
-
else
-
8
!empty?
-
end
-
end
-
-
# Returns true if there is more than one record.
-
1
def many?
-
15
if block_given?
-
18
to_a.many? { |*block_args| yield(*block_args) }
-
else
-
12
limit_value ? to_a.many? : size > 1
-
end
-
end
-
-
# Scope all queries to the current scope.
-
#
-
# Comment.where(post_id: 1).scoping do
-
# Comment.first # SELECT * FROM comments WHERE post_id = 1
-
# end
-
#
-
# Please check unscoped if you want to remove all previous scopes (including
-
# the default_scope) during the execution of a block.
-
1
def scoping
-
9325
previous, klass.current_scope = klass.current_scope, self
-
9325
yield
-
ensure
-
9325
klass.current_scope = previous
-
end
-
-
# Updates all records with details given if they match a set of conditions supplied, limits and order can
-
# also be supplied. This method constructs a single SQL UPDATE statement and sends it straight to the
-
# database. It does not instantiate the involved models and it does not trigger Active Record callbacks
-
# or validations.
-
#
-
# ==== Parameters
-
#
-
# * +updates+ - A string, array, or hash representing the SET part of an SQL statement.
-
#
-
# ==== Examples
-
#
-
# # Update all customers with the given attributes
-
# Customer.update_all wants_email: true
-
#
-
# # Update all books with 'Rails' in their title
-
# Book.where('title LIKE ?', '%Rails%').update_all(author: 'David')
-
#
-
# # Update all books that match conditions, but limit it to 5 ordered by date
-
# Book.where('title LIKE ?', '%Rails%').order(:created_at).limit(5).update_all(author: 'David')
-
1
def update_all(updates)
-
311
raise ArgumentError, "Empty list of attributes to change" if updates.blank?
-
-
310
stmt = Arel::UpdateManager.new(arel.engine)
-
-
310
stmt.set Arel.sql(@klass.send(:sanitize_sql_for_assignment, updates))
-
310
stmt.table(table)
-
310
stmt.key = table[primary_key]
-
-
310
if joins_values.any?
-
5
@klass.connection.join_to_update(stmt, arel)
-
else
-
305
stmt.take(arel.limit)
-
305
stmt.order(*arel.orders)
-
305
stmt.wheres = arel.constraints
-
end
-
-
310
@klass.connection.update stmt, 'SQL', bind_values
-
end
-
-
# Updates an object (or multiple objects) and saves it to the database, if validations pass.
-
# The resulting object is returned whether the object was saved successfully to the database or not.
-
#
-
# ==== Parameters
-
#
-
# * +id+ - This should be the id or an array of ids to be updated.
-
# * +attributes+ - This should be a hash of attributes or an array of hashes.
-
#
-
# ==== Examples
-
#
-
# # Updates one record
-
# Person.update(15, user_name: 'Samuel', group: 'expert')
-
#
-
# # Updates multiple records
-
# people = { 1 => { "first_name" => "David" }, 2 => { "first_name" => "Jeremy" } }
-
# Person.update(people.keys, people.values)
-
1
def update(id, attributes)
-
3
if id.is_a?(Array)
-
3
id.map.with_index { |one_id, idx| update(one_id, attributes[idx]) }
-
else
-
2
object = find(id)
-
2
object.update_attributes(attributes)
-
2
object
-
end
-
end
-
-
# Destroys the records matching +conditions+ by instantiating each
-
# record and calling its +destroy+ method. Each object's callbacks are
-
# executed (including <tt>:dependent</tt> association options and
-
# +before_destroy+/+after_destroy+ Observer methods). Returns the
-
# collection of objects that were destroyed; each will be frozen, to
-
# reflect that no changes should be made (since they can't be
-
# persisted).
-
#
-
# Note: Instantiation, callback execution, and deletion of each
-
# record can be time consuming when you're removing many records at
-
# once. It generates at least one SQL +DELETE+ query per record (or
-
# possibly more, to enforce your callbacks). If you want to delete many
-
# rows quickly, without concern for their associations or callbacks, use
-
# +delete_all+ instead.
-
#
-
# ==== Parameters
-
#
-
# * +conditions+ - A string, array, or hash that specifies which records
-
# to destroy. If omitted, all records are destroyed. See the
-
# Conditions section in the introduction to ActiveRecord::Base for
-
# more information.
-
#
-
# ==== Examples
-
#
-
# Person.destroy_all("last_login < '2004-04-04'")
-
# Person.destroy_all(status: "inactive")
-
# Person.where(age: 0..18).destroy_all
-
1
def destroy_all(conditions = nil)
-
20
if conditions
-
1
where(conditions).destroy_all
-
else
-
76
to_a.each {|object| object.destroy }.tap { reset }
-
end
-
end
-
-
# Destroy an object (or multiple objects) that has the given id. The object is instantiated first,
-
# therefore all callbacks and filters are fired off before the object is deleted. This method is
-
# less efficient than ActiveRecord#delete but allows cleanup methods and other actions to be run.
-
#
-
# This essentially finds the object (or multiple objects) with the given id, creates a new object
-
# from the attributes, and then calls destroy on it.
-
#
-
# ==== Parameters
-
#
-
# * +id+ - Can be either an Integer or an Array of Integers.
-
#
-
# ==== Examples
-
#
-
# # Destroy a single object
-
# Todo.destroy(1)
-
#
-
# # Destroy multiple objects
-
# todos = [1,2,3]
-
# Todo.destroy(todos)
-
1
def destroy(id)
-
4
if id.is_a?(Array)
-
3
id.map { |one_id| destroy(one_id) }
-
else
-
3
find(id).destroy
-
end
-
end
-
-
# Deletes the records matching +conditions+ without instantiating the records
-
# first, and hence not calling the +destroy+ method nor invoking callbacks. This
-
# is a single SQL DELETE statement that goes straight to the database, much more
-
# efficient than +destroy_all+. Be careful with relations though, in particular
-
# <tt>:dependent</tt> rules defined on associations are not honored. Returns the
-
# number of rows affected.
-
#
-
# Post.delete_all("person_id = 5 AND (category = 'Something' OR category = 'Else')")
-
# Post.delete_all(["person_id = ? AND (category = ? OR category = ?)", 5, 'Something', 'Else'])
-
# Post.where(person_id: 5).where(category: ['Something', 'Else']).delete_all
-
#
-
# Both calls delete the affected posts all at once with a single DELETE statement.
-
# If you need to destroy dependent associations or call your <tt>before_*</tt> or
-
# +after_destroy+ callbacks, use the +destroy_all+ method instead.
-
#
-
# If a limit scope is supplied, +delete_all+ raises an ActiveRecord error:
-
#
-
# Post.limit(100).delete_all
-
# # => ActiveRecord::ActiveRecordError: delete_all doesn't support limit scope
-
1
def delete_all(conditions = nil)
-
483
raise ActiveRecordError.new("delete_all doesn't support limit scope") if self.limit_value
-
-
482
if conditions
-
32
where(conditions).delete_all
-
else
-
450
stmt = Arel::DeleteManager.new(arel.engine)
-
450
stmt.from(table)
-
-
450
if joins_values.any?
-
2
@klass.connection.join_to_delete(stmt, arel, table[primary_key])
-
else
-
448
stmt.wheres = arel.constraints
-
end
-
-
450
affected = @klass.connection.delete(stmt, 'SQL', bind_values)
-
-
450
reset
-
450
affected
-
end
-
end
-
-
# Deletes the row with a primary key matching the +id+ argument, using a
-
# SQL +DELETE+ statement, and returns the number of rows deleted. Active
-
# Record objects are not instantiated, so the object's callbacks are not
-
# executed, including any <tt>:dependent</tt> association options or
-
# Observer methods.
-
#
-
# You can delete multiple rows at once by passing an Array of <tt>id</tt>s.
-
#
-
# Note: Although it is often much faster than the alternative,
-
# <tt>#destroy</tt>, skipping callbacks might bypass business logic in
-
# your application that ensures referential integrity or performs other
-
# essential jobs.
-
#
-
# ==== Examples
-
#
-
# # Delete a single row
-
# Todo.delete(1)
-
#
-
# # Delete multiple rows
-
# Todo.delete([2,3,4])
-
1
def delete(id_or_array)
-
26
where(primary_key => id_or_array).delete_all
-
end
-
-
# Causes the records to be loaded from the database if they have not
-
# been loaded already. You can use this if for some reason you need
-
# to explicitly load some records before actually using them. The
-
# return value is the relation itself, not the records.
-
#
-
# Post.where(published: true).load # => #<ActiveRecord::Relation>
-
1
def load
-
7071
unless loaded?
-
# We monitor here the entire execution rather than individual SELECTs
-
# because from the point of view of the user fetching the records of a
-
# relation is a single unit of work. You want to know if this call takes
-
# too long, not if the individual queries take too long.
-
#
-
# It could be the case that none of the queries involved surpass the
-
# threshold, and at the same time the sum of them all does. The user
-
# should get a query plan logged in that case.
-
14050
logging_query_plan { exec_queries }
-
end
-
-
7055
self
-
end
-
-
# Forces reloading of relation.
-
1
def reload
-
4
reset
-
4
load
-
end
-
-
1
def reset
-
35364
@first = @last = @to_sql = @order_clause = @scope_for_create = @arel = @loaded = nil
-
35364
@should_eager_load = @join_dependency = nil
-
35364
@records = []
-
35364
self
-
end
-
-
# Returns sql statement for the relation.
-
#
-
# Users.where(name: 'Oscar').to_sql
-
# # => SELECT "users".* FROM "users" WHERE "users"."name" = 'Oscar'
-
1
def to_sql
-
797
@to_sql ||= klass.connection.to_sql(arel, bind_values.dup)
-
end
-
-
# Returns a hash of where conditions
-
#
-
# Users.where(name: 'Oscar').where_values_hash
-
# # => {:name=>"oscar"}
-
1
def where_values_hash
-
872
equalities = with_default_scope.where_values.grep(Arel::Nodes::Equality).find_all { |node|
-
1013
node.left.relation.name == table_name
-
}
-
-
1632
binds = Hash[bind_values.find_all(&:first).map { |column, v| [column.name, v] }]
-
-
872
Hash[equalities.map { |where|
-
835
name = where.left.name
-
1082
[name, binds.fetch(name.to_s) { where.right }]
-
}]
-
end
-
-
1
def scope_for_create
-
957
@scope_for_create ||= where_values_hash.merge(create_with_value)
-
end
-
-
# Returns true if relation needs eager loading.
-
1
def eager_loading?
-
@should_eager_load ||=
-
eager_load_values.any? ||
-
14783
includes_values.any? && (joined_includes_values.any? || references_eager_loaded_tables?)
-
end
-
-
# Joins that are also marked for preloading. In which case we should just eager load them.
-
# Note that this is a naive implementation because we could have strings and symbols which
-
# represent the same association, but that aren't matched by this. Also, we could have
-
# nested hashes which partially match, e.g. { a: :b } & { a: [:b, :c] }
-
1
def joined_includes_values
-
726
includes_values & joins_values
-
end
-
-
# Compares two relations for equality.
-
1
def ==(other)
-
67
case other
-
when Relation
-
16
other.to_sql == to_sql
-
when Array
-
50
to_a == other
-
end
-
end
-
-
1
def pretty_print(q)
-
q.pp(self.to_a)
-
end
-
-
1
def with_default_scope #:nodoc:
-
24583
if default_scoped? && default_scope = klass.send(:build_default_scope)
-
199
default_scope = default_scope.merge(self)
-
199
default_scope.default_scoped = false
-
199
default_scope
-
else
-
24384
self
-
end
-
end
-
-
# Returns true if relation is blank.
-
1
def blank?
-
86
to_a.blank?
-
end
-
-
1
def values
-
15411
Hash[@values]
-
end
-
-
1
def inspect
-
8
entries = to_a.take([limit_value, 11].compact.min).map!(&:inspect)
-
8
entries[10] = '...' if entries.size == 11
-
-
8
"#<#{self.class.name} [#{entries.join(', ')}]>"
-
end
-
-
1
private
-
-
1
def exec_queries
-
7023
default_scoped = with_default_scope
-
-
7023
if default_scoped.equal?(self)
-
6965
@records = eager_loading? ? find_with_associations : @klass.find_by_sql(arel, bind_values)
-
-
6953
preload = preload_values
-
6953
preload += includes_values unless eager_loading?
-
6953
preload.each do |associations|
-
360
ActiveRecord::Associations::Preloader.new(@records, associations).run
-
end
-
-
# @readonly_value is true only if set explicitly. @implicit_readonly is true if there
-
# are JOINS and no explicit SELECT.
-
6949
readonly = readonly_value.nil? ? @implicit_readonly : readonly_value
-
7123
@records.each { |record| record.readonly! } if readonly
-
else
-
58
@records = default_scoped.to_a
-
end
-
-
7007
@loaded = true
-
7007
@records
-
end
-
-
1
def references_eager_loaded_tables?
-
744
joined_tables = arel.join_sources.map do |join|
-
202
if join.is_a?(Arel::Nodes::StringJoin)
-
8
tables_in_string(join.left)
-
else
-
194
[join.left.table_name, join.left.table_alias]
-
end
-
end
-
-
744
joined_tables += [table.name, table.table_alias]
-
-
# always convert table names to downcase as in Oracle quoted table names are in uppercase
-
1706
joined_tables = joined_tables.flatten.compact.map { |t| t.downcase }.uniq
-
744
string_tables = tables_in_string(to_sql)
-
-
744
if (references_values - joined_tables).any?
-
96
true
-
648
elsif (string_tables - joined_tables).any?
-
6
ActiveSupport::Deprecation.warn(
-
"It looks like you are eager loading table(s) (one of: #{string_tables.join(', ')}) " \
-
"that are referenced in a string SQL snippet. For example: \n" \
-
"\n" \
-
" Post.includes(:comments).where(\"comments.title = 'foo'\")\n" \
-
"\n" \
-
"Currently, Active Record recognises the table in the string, and knows to JOIN the " \
-
"comments table to the query, rather than loading comments in a separate query. " \
-
"However, doing this without writing a full-blown SQL parser is inherently flawed. " \
-
"Since we don't want to write an SQL parser, we are removing this functionality. " \
-
"From now on, you must explicitly tell Active Record when you are referencing a table " \
-
"from a string:\n" \
-
"\n" \
-
" Post.includes(:comments).where(\"comments.title = 'foo'\").references(:comments)\n\n"
-
)
-
6
true
-
else
-
642
false
-
end
-
end
-
-
1
def tables_in_string(string)
-
752
return [] if string.blank?
-
# always convert table names to downcase as in Oracle quoted table names are in uppercase
-
# ignore raw_sql_ that is used by Oracle adapter as alias for limit/offset subqueries
-
2944
string.scan(/([a-zA-Z_][.\w]+).?\./).flatten.map{ |s| s.downcase }.uniq - ['raw_sql_']
-
end
-
end
-
end
-
-
1
module ActiveRecord
-
1
module Batches
-
# Looping through a collection of records from the database
-
# (using the +all+ method, for example) is very inefficient
-
# since it will try to instantiate all the objects at once.
-
#
-
# In that case, batch processing methods allow you to work
-
# with the records in batches, thereby greatly reducing memory consumption.
-
#
-
# The #find_each method uses #find_in_batches with a batch size of 1000 (or as
-
# specified by the +:batch_size+ option).
-
#
-
# Person.all.find_each do |person|
-
# person.do_awesome_stuff
-
# end
-
#
-
# Person.where("age > 21").find_each do |person|
-
# person.party_all_night!
-
# end
-
#
-
# You can also pass the +:start+ option to specify
-
# an offset to control the starting point.
-
1
def find_each(options = {})
-
10
find_in_batches(options) do |records|
-
95
records.each { |record| yield record }
-
end
-
end
-
-
# Yields each batch of records that was found by the find +options+ as
-
# an array. The size of each batch is set by the +:batch_size+
-
# option; the default is 1000.
-
#
-
# You can control the starting point for the batch processing by
-
# supplying the +:start+ option. This is especially useful if you
-
# want multiple workers dealing with the same processing queue. You can
-
# make worker 1 handle all the records between id 0 and 10,000 and
-
# worker 2 handle from 10,000 and beyond (by setting the +:start+
-
# option on that worker).
-
#
-
# It's not possible to set the order. That is automatically set to
-
# ascending on the primary key ("id ASC") to make the batch ordering
-
# work. This also means that this method only works with integer-based
-
# primary keys. You can't set the limit either, that's used to control
-
# the batch sizes.
-
#
-
# Person.where("age > 21").find_in_batches do |group|
-
# sleep(50) # Make sure it doesn't get too crowded in there!
-
# group.each { |person| person.party_all_night! }
-
# end
-
#
-
# # Let's process the next 2000 records
-
# Person.all.find_in_batches(start: 2000, batch_size: 2000) do |group|
-
# group.each { |person| person.party_all_night! }
-
# end
-
1
def find_in_batches(options = {})
-
21
options.assert_valid_keys(:start, :batch_size)
-
-
21
relation = self
-
-
21
unless arel.orders.blank? && arel.taken.blank?
-
6
ActiveRecord::Base.logger.warn("Scoped order and limit are ignored, it's forced to be batch order and batch size")
-
end
-
-
21
start = options.delete(:start)
-
21
batch_size = options.delete(:batch_size) || 1000
-
-
21
relation = relation.reorder(batch_order).limit(batch_size)
-
21
records = start ? relation.where(table[primary_key].gteq(start)).to_a : relation.to_a
-
-
21
while records.any?
-
82
records_size = records.size
-
82
primary_key_offset = records.last.id
-
-
82
yield records
-
-
82
break if records_size < batch_size
-
-
74
if primary_key_offset
-
73
records = relation.where(table[primary_key].gt(primary_key_offset)).to_a
-
else
-
1
raise "Primary key not included in the custom select clause"
-
end
-
end
-
end
-
-
1
private
-
-
1
def batch_order
-
21
"#{quoted_table_name}.#{quoted_primary_key} ASC"
-
end
-
end
-
end
-
1
require 'active_support/core_ext/object/try'
-
-
1
module ActiveRecord
-
1
module Calculations
-
# Count the records.
-
#
-
# Person.count
-
# # => the total count of all people
-
#
-
# Person.count(:age)
-
# # => returns the total count of all people whose age is present in database
-
#
-
# Person.count(:all)
-
# # => performs a COUNT(*) (:all is an alias for '*')
-
#
-
# Person.count(:age, distinct: true)
-
# # => counts the number of different age values
-
#
-
# Person.where("age > 26").count { |person| person.gender == 'female' }
-
# # => queries people where "age > 26" then count the loaded results filtering by gender
-
1
def count(column_name = nil, options = {})
-
736
if block_given?
-
35
self.to_a.count { |item| yield item }
-
else
-
731
column_name, options = nil, column_name if column_name.is_a?(Hash)
-
731
calculate(:count, column_name, options)
-
end
-
end
-
-
# Calculates the average value on a given column. Returns +nil+ if there's
-
# no row. See +calculate+ for examples with options.
-
#
-
# Person.average('age') # => 35.8
-
1
def average(column_name, options = {})
-
10
calculate(:average, column_name, options)
-
end
-
-
# Calculates the minimum value on a given column. The value is returned
-
# with the same data type of the column, or +nil+ if there's no row. See
-
# +calculate+ for examples with options.
-
#
-
# Person.minimum('age') # => 7
-
1
def minimum(column_name, options = {})
-
6
calculate(:minimum, column_name, options)
-
end
-
-
# Calculates the maximum value on a given column. The value is returned
-
# with the same data type of the column, or +nil+ if there's no row. See
-
# +calculate+ for examples with options.
-
#
-
# Person.maximum('age') # => 93
-
1
def maximum(column_name, options = {})
-
13
calculate(:maximum, column_name, options)
-
end
-
-
# Calculates the sum of values on a given column. The value is returned
-
# with the same data type of the column, 0 if there's no row. See
-
# +calculate+ for examples with options.
-
#
-
# Person.sum('age') # => 4562
-
# # => returns the total sum of all people's age
-
#
-
# Person.where('age > 100').sum { |person| person.age - 100 }
-
# # queries people where "age > 100" then perform a sum calculation with the block returns
-
1
def sum(*args)
-
37
if block_given?
-
28
self.to_a.sum(*args) { |item| yield item }
-
else
-
33
calculate(:sum, *args)
-
end
-
end
-
-
# This calculates aggregate values in the given column. Methods for count, sum, average,
-
# minimum, and maximum have been added as shortcuts.
-
#
-
# There are two basic forms of output:
-
#
-
# * Single aggregate value: The single value is type cast to Fixnum for COUNT, Float
-
# for AVG, and the given column's type for everything else.
-
#
-
# * Grouped values: This returns an ordered hash of the values and groups them. It
-
# takes either a column name, or the name of a belongs_to association.
-
#
-
# values = Person.group('last_name').maximum(:age)
-
# puts values["Drake"]
-
# => 43
-
#
-
# drake = Family.find_by_last_name('Drake')
-
# values = Person.group(:family).maximum(:age) # Person belongs_to :family
-
# puts values[drake]
-
# => 43
-
#
-
# values.each do |family, max_age|
-
# ...
-
# end
-
#
-
# Examples:
-
# Person.calculate(:count, :all) # The same as Person.count
-
# Person.average(:age) # SELECT AVG(age) FROM people...
-
#
-
# # Selects the minimum age for any family without any minors
-
# Person.group(:last_name).having("min(age) > 17").minimum(:age)
-
#
-
# Person.sum("2 * age")
-
1
def calculate(operation, column_name, options = {})
-
820
relation = with_default_scope
-
-
820
if relation.equal?(self)
-
813
if has_include?(column_name)
-
17
construct_relation_for_association_calculations.calculate(operation, column_name, options)
-
else
-
796
perform_calculation(operation, column_name, options)
-
end
-
else
-
7
relation.calculate(operation, column_name, options)
-
end
-
rescue ThrowResult
-
1
0
-
end
-
-
# Use <tt>pluck</tt> as a shortcut to select a single attribute without
-
# loading a bunch of records just to grab one attribute you want.
-
#
-
# Person.pluck(:name)
-
#
-
# instead of
-
#
-
# Person.all.map(&:name)
-
#
-
# Pluck returns an <tt>Array</tt> of attribute values type-casted to match
-
# the plucked column name, if it can be deduced. Plucking an SQL fragment
-
# returns String values by default.
-
#
-
# Examples:
-
#
-
# Person.pluck(:id)
-
# # SELECT people.id FROM people
-
# # => [1, 2, 3]
-
#
-
# Person.pluck(:id, :name)
-
# # SELECT people.id, people.name FROM people
-
# # => [[1, 'David'], [2, 'Jeremy'], [3, 'Jose']]
-
#
-
# Person.uniq.pluck(:role)
-
# # SELECT DISTINCT role FROM people
-
# # => ['admin', 'member', 'guest']
-
#
-
# Person.where(:age => 21).limit(5).pluck(:id)
-
# # SELECT people.id FROM people WHERE people.age = 21 LIMIT 5
-
# # => [2, 3]
-
#
-
# Person.pluck('DATEDIFF(updated_at, created_at)')
-
# # SELECT DATEDIFF(updated_at, created_at) FROM people
-
# # => ['0', '27761', '173']
-
#
-
1
def pluck(*column_names)
-
46
column_names.map! do |column_name|
-
51
if column_name.is_a?(Symbol) && self.column_names.include?(column_name.to_s)
-
17
"#{connection.quote_table_name(table_name)}.#{connection.quote_column_name(column_name)}"
-
else
-
34
column_name
-
end
-
end
-
-
46
if has_include?(column_names.first)
-
6
construct_relation_for_association_calculations.pluck(*column_names)
-
else
-
40
result = klass.connection.select_all(select(column_names).arel, nil, bind_values)
-
40
columns = result.columns.map do |key|
-
45
klass.column_types.fetch(key) {
-
3
result.column_types.fetch(key) {
-
Class.new { def type_cast(v); v; end }.new
-
}
-
}
-
end
-
-
40
result = result.map do |attributes|
-
112
values = klass.initialize_attributes(attributes).values
-
-
112
columns.zip(values).map do |column, value|
-
141
column.type_cast(value)
-
end
-
end
-
40
columns.one? ? result.map!(&:first) : result
-
end
-
end
-
-
# Pluck all the ID's for the relation using the table's primary key
-
#
-
# Examples:
-
#
-
# Person.ids # SELECT people.id FROM people
-
# Person.joins(:companies).ids # SELECT people.id FROM people INNER JOIN companies ON companies.person_id = people.id
-
1
def ids
-
1
pluck primary_key
-
end
-
-
1
private
-
-
1
def has_include?(column_name)
-
859
eager_loading? || (includes_values.present? && (column_name || references_eager_loaded_tables?))
-
end
-
-
1
def perform_calculation(operation, column_name, options = {})
-
796
operation = operation.to_s.downcase
-
-
796
distinct = options[:distinct]
-
-
796
if operation == "count"
-
734
column_name ||= (select_for_count || :all)
-
-
734
unless arel.ast.grep(Arel::Nodes::OuterJoin).empty?
-
12
distinct = true
-
end
-
-
734
column_name = primary_key if column_name == :all && distinct
-
-
734
distinct = nil if column_name =~ /\s*DISTINCT\s+/i
-
end
-
-
796
if group_values.any?
-
31
execute_grouped_calculation(operation, column_name, distinct)
-
else
-
765
execute_simple_calculation(operation, column_name, distinct)
-
end
-
end
-
-
1
def aggregate_column(column_name)
-
793
if @klass.column_names.include?(column_name.to_s)
-
118
Arel::Attribute.new(@klass.unscoped.table, column_name)
-
else
-
675
Arel.sql(column_name == :all ? "*" : column_name.to_s)
-
end
-
end
-
-
1
def operation_over_aggregate_column(column, operation, distinct)
-
793
operation == 'count' ? column.count(distinct) : column.send(operation)
-
end
-
-
1
def execute_simple_calculation(operation, column_name, distinct) #:nodoc:
-
# Postgresql doesn't like ORDER BY when there are no GROUP BY
-
765
relation = reorder(nil)
-
-
765
if operation == "count" && (relation.limit_value || relation.offset_value)
-
# Shortcut when limit is zero.
-
17
return 0 if relation.limit_value == 0
-
-
14
query_builder = build_count_subquery(relation, column_name, distinct)
-
else
-
748
column = aggregate_column(column_name)
-
-
748
select_value = operation_over_aggregate_column(column, operation, distinct)
-
-
748
relation.select_values = [select_value]
-
-
748
query_builder = relation.arel
-
end
-
-
762
result = @klass.connection.select_value(query_builder, nil, relation.bind_values)
-
762
type_cast_calculated_value(result, column_for(column_name), operation)
-
end
-
-
1
def execute_grouped_calculation(operation, column_name, distinct) #:nodoc:
-
31
group_attrs = group_values
-
-
31
if group_attrs.first.respond_to?(:to_sym)
-
30
association = @klass.reflect_on_association(group_attrs.first.to_sym)
-
30
associated = group_attrs.size == 1 && association && association.macro == :belongs_to # only count belongs_to associations
-
30
group_fields = Array(associated ? association.foreign_key : group_attrs)
-
else
-
1
group_fields = group_attrs
-
end
-
-
64
group_aliases = group_fields.map { |field| column_alias_for(field) }
-
31
group_columns = group_aliases.zip(group_fields).map { |aliaz,field|
-
33
[aliaz, column_for(field)]
-
}
-
-
31
group = @klass.connection.adapter_name == 'FrontBase' ? group_aliases : group_fields
-
-
31
if operation == 'count' && column_name == :all
-
8
aggregate_alias = 'count_all'
-
else
-
23
aggregate_alias = column_alias_for(operation, column_name)
-
end
-
-
31
select_values = [
-
operation_over_aggregate_column(
-
aggregate_column(column_name),
-
operation,
-
distinct).as(aggregate_alias)
-
]
-
31
select_values += select_values unless having_values.empty?
-
-
31
select_values.concat group_fields.zip(group_aliases).map { |field,aliaz|
-
33
if field.respond_to?(:as)
-
1
field.as(aliaz)
-
else
-
32
"#{field} AS #{aliaz}"
-
end
-
}
-
-
31
relation = except(:group).group(group)
-
31
relation.select_values = select_values
-
-
31
calculated_data = @klass.connection.select_all(relation, nil, bind_values)
-
-
31
if association
-
20
key_ids = calculated_data.collect { |row| row[group_aliases.first] }
-
4
key_records = association.klass.base_class.find(key_ids)
-
17
key_records = Hash[key_records.map { |r| [r.id, r] }]
-
end
-
-
31
Hash[calculated_data.map do |row|
-
112
key = group_columns.map { |aliaz, column|
-
122
type_cast_calculated_value(row[aliaz], column)
-
}
-
112
key = key.first if key.size == 1
-
112
key = key_records[key] if associated
-
112
[key, type_cast_calculated_value(row[aggregate_alias], column_for(column_name), operation)]
-
end]
-
end
-
-
# Converts the given keys to the value that the database adapter returns as
-
# a usable column name:
-
#
-
# column_alias_for("users.id") # => "users_id"
-
# column_alias_for("sum(id)") # => "sum_id"
-
# column_alias_for("count(distinct users.id)") # => "count_distinct_users_id"
-
# column_alias_for("count(*)") # => "count_all"
-
# column_alias_for("count", "id") # => "count_id"
-
1
def column_alias_for(*keys)
-
135
keys.map! {|k| k.respond_to?(:to_sql) ? k.to_sql : k}
-
56
table_name = keys.join(' ')
-
56
table_name.downcase!
-
56
table_name.gsub!(/\*/, 'all')
-
56
table_name.gsub!(/\W+/, ' ')
-
56
table_name.strip!
-
56
table_name.gsub!(/ +/, '_')
-
-
56
@klass.connection.table_alias_for(table_name)
-
end
-
-
1
def column_for(field)
-
907
field_name = field.respond_to?(:name) ? field.name.to_s : field.to_s.split('.').last
-
907
@klass.columns_hash[field_name]
-
end
-
-
1
def type_cast_calculated_value(value, column, operation = nil)
-
998
case operation
-
776
when 'count' then value.to_i
-
69
when 'sum' then type_cast_using_column(value || 0, column)
-
10
when 'average' then value.respond_to?(:to_d) ? value.to_d : value
-
143
else type_cast_using_column(value, column)
-
end
-
end
-
-
1
def type_cast_using_column(value, column)
-
212
column ? column.type_cast(value) : value
-
end
-
-
1
def select_for_count
-
678
if select_values.present?
-
18
select = select_values.join(", ")
-
18
select if select !~ /[,*]/
-
end
-
end
-
-
1
def build_count_subquery(relation, column_name, distinct)
-
14
column_alias = Arel.sql('count_column')
-
14
subquery_alias = Arel.sql('subquery_for_count')
-
-
14
aliased_column = aggregate_column(column_name == :all ? 1 : column_name).as(column_alias)
-
14
relation.select_values = [aliased_column]
-
14
subquery = relation.arel.as(subquery_alias)
-
-
14
sm = Arel::SelectManager.new relation.engine
-
14
select_value = operation_over_aggregate_column(column_alias, 'count', distinct)
-
14
sm.project(select_value).from(subquery)
-
end
-
end
-
end
-
1
require 'thread'
-
-
1
module ActiveRecord
-
1
module Delegation # :nodoc:
-
# Set up common delegations for performance (avoids method_missing)
-
1
delegate :to_xml, :to_yaml, :length, :collect, :map, :each, :all?, :include?, :to_ary, :to => :to_a
-
1
delegate :table_name, :quoted_table_name, :primary_key, :quoted_primary_key,
-
:connection, :columns_hash, :auto_explain_threshold_in_seconds, :to => :klass
-
-
1
@@delegation_mutex = Mutex.new
-
-
1
def self.delegate_to_scoped_klass(method)
-
48
if method.to_s =~ /\A[a-zA-Z_]\w*[!?]?\z/
-
48
module_eval <<-RUBY, __FILE__, __LINE__ + 1
-
def #{method}(*args, &block)
-
scoping { @klass.#{method}(*args, &block) }
-
end
-
RUBY
-
else
-
module_eval <<-RUBY, __FILE__, __LINE__ + 1
-
def #{method}(*args, &block)
-
scoping { @klass.send(#{method.inspect}, *args, &block) }
-
end
-
RUBY
-
end
-
end
-
-
1
def respond_to?(method, include_private = false)
-
750
super || Array.method_defined?(method) ||
-
@klass.respond_to?(method, include_private) ||
-
arel.respond_to?(method, include_private)
-
end
-
-
1
protected
-
-
1
def method_missing(method, *args, &block)
-
65
if @klass.respond_to?(method)
-
48
@@delegation_mutex.synchronize do
-
48
unless ::ActiveRecord::Delegation.method_defined?(method)
-
48
::ActiveRecord::Delegation.delegate_to_scoped_klass(method)
-
end
-
end
-
-
96
scoping { @klass.send(method, *args, &block) }
-
17
elsif Array.method_defined?(method)
-
12
@@delegation_mutex.synchronize do
-
12
unless ::ActiveRecord::Delegation.method_defined?(method)
-
12
::ActiveRecord::Delegation.delegate method, :to => :to_a
-
end
-
end
-
-
12
to_a.send(method, *args, &block)
-
5
elsif arel.respond_to?(method)
-
4
@@delegation_mutex.synchronize do
-
4
unless ::ActiveRecord::Delegation.method_defined?(method)
-
4
::ActiveRecord::Delegation.delegate method, :to => :arel
-
end
-
end
-
-
4
arel.send(method, *args, &block)
-
else
-
1
super
-
end
-
end
-
end
-
end
-
1
module ActiveRecord
-
1
module FinderMethods
-
# Find by id - This can either be a specific id (1), a list of ids (1, 5, 6), or an array of ids ([5, 6, 10]).
-
# If no record can be found for all of the listed ids, then RecordNotFound will be raised. If the primary key
-
# is an integer, find by id coerces its arguments using +to_i+.
-
#
-
# Person.find(1) # returns the object for ID = 1
-
# Person.find("1") # returns the object for ID = 1
-
# Person.find(1, 2, 6) # returns an array for objects with IDs in (1, 2, 6)
-
# Person.find([7, 17]) # returns an array for objects with IDs in (7, 17)
-
# Person.find([1]) # returns an array for the object with ID = 1
-
# Person.where("administrator = 1").order("created_on DESC").find(1)
-
#
-
# Note that returned records may not be in the same order as the ids you
-
# provide since database rows are unordered. Give an explicit <tt>order</tt>
-
# to ensure the results are sorted.
-
#
-
# ==== Find with lock
-
#
-
# Example for find with a lock: Imagine two concurrent transactions:
-
# each will read <tt>person.visits == 2</tt>, add 1 to it, and save, resulting
-
# in two saves of <tt>person.visits = 3</tt>. By locking the row, the second
-
# transaction has to wait until the first is finished; we get the
-
# expected <tt>person.visits == 4</tt>.
-
#
-
# Person.transaction do
-
# person = Person.lock(true).find(1)
-
# person.visits += 1
-
# person.save!
-
# end
-
1
def find(*args)
-
3673
if block_given?
-
53
to_a.find { |*block_args| yield(*block_args) }
-
else
-
3665
find_with_ids(*args)
-
end
-
end
-
-
# Finds the first record matching the specified conditions. There
-
# is no implied ording so if order matters, you should specify it
-
# yourself.
-
#
-
# If no record is found, returns <tt>nil</tt>.
-
#
-
# Post.find_by name: 'Spartacus', rating: 4
-
# Post.find_by "published_at < ?", 2.weeks.ago
-
1
def find_by(*args)
-
91
where(*args).take
-
end
-
-
# Like <tt>find_by</tt>, except that if no record is found, raises
-
# an <tt>ActiveRecord::RecordNotFound</tt> error.
-
1
def find_by!(*args)
-
10
where(*args).take!
-
end
-
-
# Gives a record (or N records if a parameter is supplied) without any implied
-
# order. The order will depend on the database implementation.
-
# If an order is supplied it will be respected.
-
#
-
# Person.take # returns an object fetched by SELECT * FROM people
-
# Person.take(5) # returns 5 objects fetched by SELECT * FROM people LIMIT 5
-
# Person.where(["name LIKE '%?'", name]).take
-
1
def take(limit = nil)
-
3663
limit ? limit(limit).to_a : find_take
-
end
-
-
# Same as +take+ but raises <tt>ActiveRecord::RecordNotFound</tt> if no record
-
# is found. Note that <tt>take!</tt> accepts no arguments.
-
1
def take!
-
12
take or raise RecordNotFound
-
end
-
-
# Find the first record (or first N records if a parameter is supplied).
-
# If no order is defined it will order by primary key.
-
#
-
# Person.first # returns the first object fetched by SELECT * FROM people
-
# Person.where(["user_name = ?", user_name]).first
-
# Person.where(["user_name = :u", { :u => user_name }]).first
-
# Person.order("created_on DESC").offset(5).first
-
# Person.first(3) # returns the first three objects fetched by SELECT * FROM people LIMIT 3
-
1
def first(limit = nil)
-
1135
if limit
-
3
if order_values.empty? && primary_key
-
3
order(arel_table[primary_key].asc).limit(limit).to_a
-
else
-
limit(limit).to_a
-
end
-
else
-
1132
find_first
-
end
-
end
-
-
# Same as +first+ but raises <tt>ActiveRecord::RecordNotFound</tt> if no record
-
# is found. Note that <tt>first!</tt> accepts no arguments.
-
1
def first!
-
4
first or raise RecordNotFound
-
end
-
-
# Find the last record (or last N records if a parameter is supplied).
-
# If no order is defined it will order by primary key.
-
#
-
# Person.last # returns the last object fetched by SELECT * FROM people
-
# Person.where(["user_name = ?", user_name]).last
-
# Person.order("created_on DESC").offset(5).last
-
# Person.last(3) # returns the last three objects fetched by SELECT * FROM people.
-
#
-
# Take note that in that last case, the results are sorted in ascending order:
-
#
-
# [#<Person id:2>, #<Person id:3>, #<Person id:4>]
-
#
-
# and not:
-
#
-
# [#<Person id:4>, #<Person id:3>, #<Person id:2>]
-
1
def last(limit = nil)
-
57
if limit
-
6
if order_values.empty? && primary_key
-
3
order(arel_table[primary_key].desc).limit(limit).reverse
-
else
-
3
to_a.last(limit)
-
end
-
else
-
51
find_last
-
end
-
end
-
-
# Same as +last+ but raises <tt>ActiveRecord::RecordNotFound</tt> if no record
-
# is found. Note that <tt>last!</tt> accepts no arguments.
-
1
def last!
-
4
last or raise RecordNotFound
-
end
-
-
# Returns +true+ if a record exists in the table that matches the +id+ or
-
# conditions given, or +false+ otherwise. The argument can take six forms:
-
#
-
# * Integer - Finds the record with this primary key.
-
# * String - Finds the record with a primary key corresponding to this
-
# string (such as <tt>'5'</tt>).
-
# * Array - Finds the record that matches these +find+-style conditions
-
# (such as <tt>['color = ?', 'red']</tt>).
-
# * Hash - Finds the record that matches these +find+-style conditions
-
# (such as <tt>{color: 'red'}</tt>).
-
# * +false+ - Returns always +false+.
-
# * No args - Returns +false+ if the table is empty, +true+ otherwise.
-
#
-
# For more information about specifying conditions as a Hash or Array,
-
# see the Conditions section in the introduction to ActiveRecord::Base.
-
#
-
# Note: You can't pass in a condition as a string (like <tt>name =
-
# 'Jamie'</tt>), since it would be sanitized and then queried against
-
# the primary key column, like <tt>id = 'name = \'Jamie\''</tt>.
-
#
-
# Person.exists?(5)
-
# Person.exists?('5')
-
# Person.exists?(['name LIKE ?', "%#{query}%"])
-
# Person.exists?(name: 'David')
-
# Person.exists?(false)
-
# Person.exists?
-
1
def exists?(conditions = :none)
-
244
conditions = conditions.id if Base === conditions
-
244
return false if !conditions
-
-
239
join_dependency = construct_join_dependency_for_association_find
-
239
relation = construct_relation_for_association_find(join_dependency)
-
237
relation = relation.except(:select, :order).select("1 AS one").limit(1)
-
-
237
case conditions
-
when Array, Hash
-
20
relation = relation.where(conditions)
-
else
-
217
relation = relation.where(table[primary_key].eq(conditions)) if conditions != :none
-
end
-
-
236
connection.select_value(relation, "#{name} Exists", relation.bind_values)
-
rescue ThrowResult
-
2
false
-
end
-
-
1
protected
-
-
1
def find_with_associations
-
96
join_dependency = construct_join_dependency_for_association_find
-
95
relation = construct_relation_for_association_find(join_dependency)
-
92
rows = connection.select_all(relation, 'SQL', relation.bind_values.dup)
-
92
join_dependency.instantiate(rows)
-
rescue ThrowResult
-
3
[]
-
end
-
-
1
def construct_join_dependency_for_association_find
-
335
including = (eager_load_values + includes_values).uniq
-
335
ActiveRecord::Associations::JoinDependency.new(@klass, including, [])
-
end
-
-
1
def construct_relation_for_association_calculations
-
23
including = (eager_load_values + includes_values).uniq
-
23
join_dependency = ActiveRecord::Associations::JoinDependency.new(@klass, including, arel.froms.first)
-
23
relation = except(:includes, :eager_load, :preload)
-
23
apply_join_dependency(relation, join_dependency)
-
end
-
-
1
def construct_relation_for_association_find(join_dependency)
-
334
relation = except(:includes, :eager_load, :preload, :select).select(join_dependency.columns)
-
334
apply_join_dependency(relation, join_dependency)
-
end
-
-
1
def apply_join_dependency(relation, join_dependency)
-
357
join_dependency.join_associations.each do |association|
-
172
relation = association.join_relation(relation)
-
end
-
-
357
limitable_reflections = using_limitable_reflections?(join_dependency.reflections)
-
-
357
if !limitable_reflections && relation.limit_value
-
37
limited_id_condition = construct_limited_ids_condition(relation.except(:select))
-
31
relation = relation.where(limited_id_condition)
-
end
-
-
351
relation = relation.except(:limit, :offset) unless limitable_reflections
-
-
351
relation
-
end
-
-
1
def construct_limited_ids_condition(relation)
-
66
orders = relation.order_values.map { |val| val.presence }.compact
-
37
values = @klass.connection.distinct("#{quoted_table_name}.#{primary_key}", orders)
-
-
37
relation = relation.dup
-
-
88
ids_array = relation.select(values).collect {|row| row[primary_key]}
-
37
ids_array.empty? ? raise(ThrowResult) : table[primary_key].in(ids_array)
-
end
-
-
1
def find_with_ids(*ids)
-
3665
expects_array = ids.first.kind_of?(Array)
-
3665
return ids.first if expects_array && ids.first.empty?
-
-
3658
ids = ids.flatten.compact.uniq
-
-
3658
case ids.size
-
when 0
-
2
raise RecordNotFound, "Couldn't find #{@klass.name} without an ID"
-
when 1
-
3557
result = find_one(ids.first)
-
3507
expects_array ? [ result ] : result
-
else
-
99
find_some(ids)
-
end
-
end
-
-
1
def find_one(id)
-
3557
id = id.id if ActiveRecord::Base === id
-
-
3557
column = columns_hash[primary_key]
-
3556
substitute = connection.substitute_at(column, bind_values.length)
-
3556
relation = where(table[primary_key].eq(substitute))
-
3556
relation.bind_values += [[column, id]]
-
3556
record = relation.take
-
-
3550
unless record
-
43
conditions = arel.where_sql
-
43
conditions = " [#{conditions}]" if conditions
-
43
raise RecordNotFound, "Couldn't find #{@klass.name} with #{primary_key}=#{id}#{conditions}"
-
end
-
-
3507
record
-
end
-
-
1
def find_some(ids)
-
99
result = where(table[primary_key].in(ids)).to_a
-
-
99
expected_size =
-
if limit_value && ids.size > limit_value
-
2
limit_value
-
else
-
97
ids.size
-
end
-
-
# 11 ids with limit 3, offset 9 should give 2 results.
-
99
if offset_value && (ids.size - offset_value < expected_size)
-
2
expected_size = ids.size - offset_value
-
end
-
-
99
if result.size == expected_size
-
94
result
-
else
-
5
conditions = arel.where_sql
-
5
conditions = " [#{conditions}]" if conditions
-
-
5
error = "Couldn't find all #{@klass.name.pluralize} with IDs "
-
5
error << "(#{ids.join(", ")})#{conditions} (found #{result.size} results, but was looking for #{expected_size})"
-
5
raise RecordNotFound, error
-
end
-
end
-
-
1
def find_take
-
3661
if loaded?
-
@records.first
-
else
-
3661
@take ||= limit(1).to_a.first
-
end
-
end
-
-
1
def find_first
-
1132
if loaded?
-
11
@records.first
-
else
-
@first ||=
-
if with_default_scope.order_values.empty? && primary_key
-
969
order(arel_table[primary_key].asc).limit(1).to_a.first
-
else
-
149
limit(1).to_a.first
-
1121
end
-
end
-
end
-
-
1
def find_last
-
51
if loaded?
-
1
@records.last
-
else
-
@last ||=
-
if offset_value || limit_value
-
3
to_a.last
-
else
-
47
reverse_order.limit(1).to_a.first
-
50
end
-
end
-
end
-
-
1
def using_limitable_reflections?(reflections)
-
507
reflections.none? { |r| r.collection? }
-
end
-
end
-
end
-
1
require 'active_support/core_ext/hash/keys'
-
-
1
module ActiveRecord
-
1
class Relation
-
1
class HashMerger # :nodoc:
-
1
attr_reader :relation, :hash
-
-
1
def initialize(relation, hash)
-
410
hash.assert_valid_keys(*Relation::VALUE_METHODS)
-
-
409
@relation = relation
-
409
@hash = hash
-
end
-
-
1
def merge
-
409
Merger.new(relation, other).merge
-
end
-
-
# Applying values to a relation has some side effects. E.g.
-
# interpolation might take place for where values. So we should
-
# build a relation to merge in rather than directly merging
-
# the values.
-
1
def other
-
409
other = Relation.new(relation.klass, relation.table)
-
409
hash.each { |k, v|
-
684
if k == :joins
-
20
if Hash === v
-
2
other.joins!(v)
-
else
-
18
other.joins!(*v)
-
end
-
else
-
664
other.send("#{k}!", v)
-
end
-
}
-
407
other
-
end
-
end
-
-
1
class Merger # :nodoc:
-
1
attr_reader :relation, :values
-
-
1
def initialize(relation, other)
-
12127
if other.default_scoped? && other.klass != relation.klass
-
1013
other = other.with_default_scope
-
end
-
-
12127
@relation = relation
-
12127
@values = other.values
-
end
-
-
1
NORMAL_VALUES = Relation::SINGLE_VALUE_METHODS +
-
Relation::MULTI_VALUE_METHODS -
-
[:where, :order, :bind, :reverse_order, :lock, :create_with, :reordering, :from] # :nodoc:
-
-
1
def normal_values
-
12127
NORMAL_VALUES
-
end
-
-
1
def merge
-
12127
normal_values.each do |name|
-
157651
value = values[name]
-
157651
relation.send("#{name}!", *value) unless value.blank?
-
end
-
-
12127
merge_multi_values
-
12126
merge_single_values
-
-
12126
relation
-
end
-
-
1
private
-
-
1
def merge_multi_values
-
12127
relation.where_values = merged_wheres
-
12126
relation.bind_values = merged_binds
-
-
12126
if values[:reordering]
-
# override any order specified in the original relation
-
3
relation.reorder! values[:order]
-
elsif values[:order]
-
# merge in order_values from r
-
3201
relation.order! values[:order]
-
end
-
-
12126
relation.extend(*values[:extending]) unless values[:extending].blank?
-
end
-
-
1
def merge_single_values
-
12126
relation.from_value = values[:from] unless relation.from_value
-
12126
relation.lock_value = values[:lock] unless relation.lock_value
-
12126
relation.reverse_order_value = values[:reverse_order]
-
-
12126
unless values[:create_with].blank?
-
1943
relation.create_with_value = (relation.create_with_value || {}).merge(values[:create_with])
-
end
-
end
-
-
1
def merged_binds
-
12126
if values[:bind]
-
9266
(relation.bind_values + values[:bind]).uniq(&:first)
-
else
-
2860
relation.bind_values
-
end
-
end
-
-
1
def merged_wheres
-
12127
if values[:where]
-
9997
merged_wheres = relation.where_values + values[:where]
-
-
9997
unless relation.where_values.empty?
-
# Remove equalities with duplicated left-hand. Last one wins.
-
1544
seen = {}
-
1544
merged_wheres = merged_wheres.reverse.reject { |w|
-
4327
nuke = false
-
4327
if w.respond_to?(:operator) && w.operator == :==
-
4202
nuke = seen[w.left]
-
4202
seen[w.left] = true
-
end
-
4327
nuke
-
}.reverse
-
end
-
-
9997
merged_wheres
-
else
-
2130
relation.where_values
-
end
-
end
-
end
-
end
-
end
-
1
module ActiveRecord
-
1
class PredicateBuilder # :nodoc:
-
1
def self.build_from_hash(klass, attributes, default_table)
-
1278
queries = []
-
-
1278
attributes.each do |column, value|
-
1376
table = default_table
-
-
1376
if value.is_a?(Hash)
-
120
table = Arel::Table.new(column, default_table.engine)
-
120
association = klass.reflect_on_association(column.to_sym)
-
-
120
if value.empty?
-
2
queries.concat ['1 = 2']
-
else
-
118
value.each do |k, v|
-
120
queries.concat expand(association && association.klass, table, k, v)
-
end
-
end
-
else
-
1256
column = column.to_s
-
-
1256
if column.include?('.')
-
64
table_name, column = column.split('.', 2)
-
64
table = Arel::Table.new(table_name, default_table.engine)
-
end
-
-
1256
queries.concat expand(klass, table, column, value)
-
end
-
end
-
-
1278
queries
-
end
-
-
1
def self.expand(klass, table, column, value)
-
1376
queries = []
-
-
# Find the foreign key when using queries such as:
-
# Post.where(:author => author)
-
#
-
# For polymorphic relationships, find the foreign key and type:
-
# PriceEstimate.where(:estimate_of => treasure)
-
1376
if klass && value.class < Base && reflection = klass.reflect_on_association(column.to_sym)
-
6
if reflection.polymorphic?
-
4
queries << build(table[reflection.foreign_type], value.class.base_class)
-
end
-
-
6
column = reflection.foreign_key
-
end
-
-
1376
queries << build(table[column.to_sym], value)
-
1376
queries
-
end
-
-
1
def self.references(attributes)
-
1278
attributes.map do |key, value|
-
1348
if value.is_a?(Hash)
-
120
key
-
else
-
1228
key = key.to_s
-
1228
key.split('.').first.to_sym if key.include?('.')
-
end
-
end.compact
-
end
-
-
1
private
-
1
def self.build(attribute, value)
-
1380
case value
-
when Array, ActiveRecord::Associations::CollectionProxy
-
332
values = value.to_a.map {|x| x.is_a?(Base) ? x.id : x}
-
332
ranges, values = values.partition {|v| v.is_a?(Range)}
-
-
119
values_predicate = if values.include?(nil)
-
2
values = values.compact
-
-
2
case values.length
-
when 0
-
1
attribute.eq(nil)
-
when 1
-
attribute.eq(values.first).or(attribute.eq(nil))
-
else
-
1
attribute.in(values).or(attribute.eq(nil))
-
end
-
else
-
117
attribute.in(values)
-
end
-
-
121
array_predicates = ranges.map { |range| attribute.in(range) }
-
119
array_predicates << values_predicate
-
121
array_predicates.inject { |composite, predicate| composite.or(predicate) }
-
when ActiveRecord::Relation
-
6
value = value.select(value.klass.arel_table[value.klass.primary_key]) if value.select_values.empty?
-
6
attribute.in(value.arel.ast)
-
when Range
-
11
attribute.in(value)
-
when ActiveRecord::Base
-
9
attribute.eq(value.id)
-
when Class
-
# FIXME: I think we need to deprecate this behavior
-
5
attribute.eq(value.name)
-
else
-
1230
attribute.eq(value)
-
end
-
end
-
end
-
end
-
1
require 'active_support/core_ext/array/wrap'
-
-
1
module ActiveRecord
-
1
module QueryMethods
-
1
extend ActiveSupport::Concern
-
-
1
Relation::MULTI_VALUE_METHODS.each do |name|
-
12
class_eval <<-CODE, __FILE__, __LINE__ + 1
-
def #{name}_values # def select_values
-
@values[:#{name}] || [] # @values[:select] || []
-
end # end
-
#
-
def #{name}_values=(values) # def select_values=(values)
-
raise ImmutableRelation if @loaded # raise ImmutableRelation if @loaded
-
@values[:#{name}] = values # @values[:select] = values
-
end # end
-
CODE
-
end
-
-
1
(Relation::SINGLE_VALUE_METHODS - [:create_with]).each do |name|
-
8
class_eval <<-CODE, __FILE__, __LINE__ + 1
-
def #{name}_value # def readonly_value
-
@values[:#{name}] # @values[:readonly]
-
end # end
-
CODE
-
end
-
-
1
Relation::SINGLE_VALUE_METHODS.each do |name|
-
9
class_eval <<-CODE, __FILE__, __LINE__ + 1
-
def #{name}_value=(value) # def readonly_value=(value)
-
raise ImmutableRelation if @loaded # raise ImmutableRelation if @loaded
-
@values[:#{name}] = value # @values[:readonly] = value
-
end # end
-
CODE
-
end
-
-
1
def create_with_value # :nodoc:
-
5638
@values[:create_with] || {}
-
end
-
-
1
alias extensions extending_values
-
-
# Specify relationships to be included in the result set. For
-
# example:
-
#
-
# users = User.includes(:address)
-
# users.each do |user|
-
# user.address.city
-
# end
-
#
-
# allows you to access the +address+ attribute of the +User+ model without
-
# firing an additional query. This will often result in a
-
# performance improvement over a simple +join+.
-
#
-
# === conditions
-
#
-
# If you want to add conditions to your included models you'll have
-
# to explicitly reference them. For example:
-
#
-
# User.includes(:posts).where('posts.name = ?', 'example')
-
#
-
# Will throw an error, but this will work:
-
#
-
# User.includes(:posts).where('posts.name = ?', 'example').references(:posts)
-
1
def includes(*args)
-
278
args.empty? ? self : spawn.includes!(*args)
-
end
-
-
# Like #includes, but modifies the relation in place.
-
1
def includes!(*args)
-
3647
args.reject! {|a| a.blank? }
-
-
1791
self.includes_values = (includes_values + args).flatten.uniq
-
1791
self
-
end
-
-
# Forces eager loading by performing a LEFT OUTER JOIN on +args+:
-
#
-
# User.eager_load(:posts)
-
# => SELECT "users"."id" AS t0_r0, "users"."name" AS t0_r1, ...
-
# FROM "users" LEFT OUTER JOIN "posts" ON "posts"."user_id" =
-
# "users"."id"
-
1
def eager_load(*args)
-
10
args.blank? ? self : spawn.eager_load!(*args)
-
end
-
-
# Like #eager_load, but modifies relation in place.
-
1
def eager_load!(*args)
-
14
self.eager_load_values += args
-
14
self
-
end
-
-
# Allows preloading of +args+, in the same way that +includes+ does:
-
#
-
# User.preload(:posts)
-
# => SELECT "posts".* FROM "posts" WHERE "posts"."user_id" IN (1, 2, 3)
-
1
def preload(*args)
-
18
args.blank? ? self : spawn.preload!(*args)
-
end
-
-
# Like #preload, but modifies relation in place.
-
1
def preload!(*args)
-
22
self.preload_values += args
-
22
self
-
end
-
-
# Used to indicate that an association is referenced by an SQL string, and should
-
# therefore be JOINed in any query rather than loaded separately.
-
#
-
# User.includes(:posts).where("posts.name = 'foo'")
-
# # => Doesn't JOIN the posts table, resulting in an error.
-
#
-
# User.includes(:posts).where("posts.name = 'foo'").references(:posts)
-
# # => Query now knows the string references posts, so adds a JOIN
-
1
def references(*args)
-
36
args.blank? ? self : spawn.references!(*args)
-
end
-
-
# Like #references, but modifies relation in place.
-
1
def references!(*args)
-
5788
args.flatten!
-
-
5788
self.references_values = (references_values + args.map!(&:to_s)).uniq
-
5788
self
-
end
-
-
# Works in two unique ways.
-
#
-
# First: takes a block so it can be used just like Array#select.
-
#
-
# Model.all.select { |m| m.field == value }
-
#
-
# This will build an array of objects from the database for the scope,
-
# converting them into an array and iterating through them using Array#select.
-
#
-
# Second: Modifies the SELECT statement for the query so that only certain
-
# fields are retrieved:
-
#
-
# Model.select(:field)
-
# # => [#<Model field:value>]
-
#
-
# Although in the above example it looks as though this method returns an
-
# array, it actually returns a relation object and can have other query
-
# methods appended to it, such as the other methods in ActiveRecord::QueryMethods.
-
#
-
# The argument to the method can also be an array of fields.
-
#
-
# Model.select(:field, :other_field, :and_one_more)
-
# # => [#<Model field: "value", other_field: "value", and_one_more: "value">]
-
#
-
# Accessing attributes of an object that do not have fields retrieved by a select
-
# will throw <tt>ActiveModel::MissingAttributeError</tt>:
-
#
-
# Model.select(:field).first.other_field
-
# # => ActiveModel::MissingAttributeError: missing attribute: other_field
-
1
def select(*fields)
-
773
if block_given?
-
12
to_a.select { |*block_args| yield(*block_args) }
-
else
-
772
raise ArgumentError, 'Call this with at least one field' if fields.empty?
-
771
spawn.select!(*fields)
-
end
-
end
-
-
# Like #select, but modifies relation in place.
-
1
def select!(*fields)
-
1291
self.select_values += fields.flatten
-
1291
self
-
end
-
-
# Allows to specify a group attribute:
-
#
-
# User.group(:name)
-
# => SELECT "users".* FROM "users" GROUP BY name
-
#
-
# Returns an array with distinct records based on the +group+ attribute:
-
#
-
# User.select([:id, :name])
-
# => [#<User id: 1, name: "Oscar">, #<User id: 2, name: "Oscar">, #<User id: 3, name: "Foo">
-
#
-
# User.group(:name)
-
# => [#<User id: 3, name: "Foo", ...>, #<User id: 2, name: "Oscar", ...>]
-
1
def group(*args)
-
62
args.blank? ? self : spawn.group!(*args)
-
end
-
-
# Like #group, but modifies relation in place.
-
1
def group!(*args)
-
126
args.flatten!
-
-
126
self.group_values += args
-
126
self
-
end
-
-
# Allows to specify an order attribute:
-
#
-
# User.order('name')
-
# => SELECT "users".* FROM "users" ORDER BY name
-
#
-
# User.order('name DESC')
-
# => SELECT "users".* FROM "users" ORDER BY name DESC
-
#
-
# User.order('name DESC, email')
-
# => SELECT "users".* FROM "users" ORDER BY name DESC, email
-
#
-
# User.order(:name)
-
# => SELECT "users".* FROM "users" ORDER BY "users"."name" ASC
-
#
-
# User.order(email: :desc)
-
# => SELECT "users".* FROM "users" ORDER BY "users"."email" DESC
-
#
-
# User.order(:name, email: :desc)
-
# => SELECT "users".* FROM "users" ORDER BY "users"."name" ASC, "users"."email" DESC
-
1
def order(*args)
-
1981
args.blank? ? self : spawn.order!(*args)
-
end
-
-
# Like #order, but modifies relation in place.
-
1
def order!(*args)
-
5424
args.flatten!
-
5424
validate_order_args args
-
-
10866
references = args.reject { |arg| Arel::Node === arg }
-
9873
references.map! { |arg| arg =~ /^([a-zA-Z]\w*)\.(\w+)/ && $1 }.compact!
-
5423
references!(references) if references.any?
-
-
5423
self.order_values = args + self.order_values
-
5423
self
-
end
-
-
# Replaces any existing order defined on the relation with the specified order.
-
#
-
# User.order('email DESC').reorder('id ASC') # generated SQL has 'ORDER BY id ASC'
-
#
-
# Subsequent calls to order on the same relation will be appended. For example:
-
#
-
# User.order('email DESC').reorder('id ASC').order('name ASC')
-
#
-
# generates a query with 'ORDER BY name ASC, id ASC'.
-
1
def reorder(*args)
-
791
args.blank? ? self : spawn.reorder!(*args)
-
end
-
-
# Like #reorder, but modifies relation in place.
-
1
def reorder!(*args)
-
795
args.flatten!
-
795
validate_order_args args
-
-
795
self.reordering_value = true
-
795
self.order_values = args
-
795
self
-
end
-
-
# Performs a joins on +args+:
-
#
-
# User.joins(:posts)
-
# => SELECT "users".* FROM "users" INNER JOIN "posts" ON "posts"."user_id" = "users"."id"
-
1
def joins(*args)
-
1322
args.compact.blank? ? self : spawn.joins!(*args.flatten)
-
end
-
-
# Like #joins, but modifies relation in place.
-
1
def joins!(*args)
-
4780
self.joins_values += args
-
4780
self
-
end
-
-
1
def bind(value)
-
1
spawn.bind!(value)
-
end
-
-
1
def bind!(value)
-
2
self.bind_values += [value]
-
2
self
-
end
-
-
# Returns a new relation, which is the result of filtering the current relation
-
# according to the conditions in the arguments.
-
#
-
# #where accepts conditions in one of several formats. In the examples below, the resulting
-
# SQL is given as an illustration; the actual query generated may be different depending
-
# on the database adapter.
-
#
-
# === string
-
#
-
# A single string, without additional arguments, is passed to the query
-
# constructor as a SQL fragment, and used in the where clause of the query.
-
#
-
# Client.where("orders_count = '2'")
-
# # SELECT * from clients where orders_count = '2';
-
#
-
# Note that building your own string from user input may expose your application
-
# to injection attacks if not done properly. As an alternative, it is recommended
-
# to use one of the following methods.
-
#
-
# === array
-
#
-
# If an array is passed, then the first element of the array is treated as a template, and
-
# the remaining elements are inserted into the template to generate the condition.
-
# Active Record takes care of building the query to avoid injection attacks, and will
-
# convert from the ruby type to the database type where needed. Elements are inserted
-
# into the string in the order in which they appear.
-
#
-
# User.where(["name = ? and email = ?", "Joe", "joe@example.com"])
-
# # SELECT * FROM users WHERE name = 'Joe' AND email = 'joe@example.com';
-
#
-
# Alternatively, you can use named placeholders in the template, and pass a hash as the
-
# second element of the array. The names in the template are replaced with the corresponding
-
# values from the hash.
-
#
-
# User.where(["name = :name and email = :email", { name: "Joe", email: "joe@example.com" }])
-
# # SELECT * FROM users WHERE name = 'Joe' AND email = 'joe@example.com';
-
#
-
# This can make for more readable code in complex queries.
-
#
-
# Lastly, you can use sprintf-style % escapes in the template. This works slightly differently
-
# than the previous methods; you are responsible for ensuring that the values in the template
-
# are properly quoted. The values are passed to the connector for quoting, but the caller
-
# is responsible for ensuring they are enclosed in quotes in the resulting SQL. After quoting,
-
# the values are inserted using the same escapes as the Ruby core method <tt>Kernel::sprintf</tt>.
-
#
-
# User.where(["name = '%s' and email = '%s'", "Joe", "joe@example.com"])
-
# # SELECT * FROM users WHERE name = 'Joe' AND email = 'joe@example.com';
-
#
-
# If #where is called with multiple arguments, these are treated as if they were passed as
-
# the elements of a single array.
-
#
-
# User.where("name = :name and email = :email", { name: "Joe", email: "joe@example.com" })
-
# # SELECT * FROM users WHERE name = 'Joe' AND email = 'joe@example.com';
-
#
-
# When using strings to specify conditions, you can use any operator available from
-
# the database. While this provides the most flexibility, you can also unintentionally introduce
-
# dependencies on the underlying database. If your code is intended for general consumption,
-
# test with multiple database backends.
-
#
-
# === hash
-
#
-
# #where will also accept a hash condition, in which the keys are fields and the values
-
# are values to be searched for.
-
#
-
# Fields can be symbols or strings. Values can be single values, arrays, or ranges.
-
#
-
# User.where({ name: "Joe", email: "joe@example.com" })
-
# # SELECT * FROM users WHERE name = 'Joe' AND email = 'joe@example.com'
-
#
-
# User.where({ name: ["Alice", "Bob"]})
-
# # SELECT * FROM users WHERE name IN ('Alice', 'Bob')
-
#
-
# User.where({ created_at: (Time.now.midnight - 1.day)..Time.now.midnight })
-
# # SELECT * FROM users WHERE (created_at BETWEEN '2012-06-09 07:00:00.000000' AND '2012-06-10 07:00:00.000000')
-
#
-
# In the case of a belongs_to relationship, an association key can be used
-
# to specify the model if an ActiveRecord object is used as the value.
-
#
-
# author = Author.find(1)
-
#
-
# # The following queries will be equivalent:
-
# Post.where(:author => author)
-
# Post.where(:author_id => author)
-
#
-
# This also works with polymorphic belongs_to relationships:
-
#
-
# treasure = Treasure.create(:name => 'gold coins')
-
# treasure.price_estimates << PriceEstimate.create(:price => 125)
-
#
-
# # The following queries will be equivalent:
-
# PriceEstimate.where(:estimate_of => treasure)
-
# PriceEstimate.where(:estimate_of_type => 'Treasure', :estimate_of_id => treasure)
-
#
-
# === Joins
-
#
-
# If the relation is the result of a join, you may create a condition which uses any of the
-
# tables in the join. For string and array conditions, use the table name in the condition.
-
#
-
# User.joins(:posts).where("posts.created_at < ?", Time.now)
-
#
-
# For hash conditions, you can either use the table name in the key, or use a sub-hash.
-
#
-
# User.joins(:posts).where({ "posts.published" => true })
-
# User.joins(:posts).where({ :posts => { :published => true } })
-
#
-
# === empty condition
-
#
-
# If the condition returns true for blank?, then where is a no-op and returns the current relation.
-
1
def where(opts, *rest)
-
12251
opts.blank? ? self : spawn.where!(opts, *rest)
-
end
-
-
# #where! is identical to #where, except that instead of returning a new relation, it adds
-
# the condition to the existing relation.
-
1
def where!(opts, *rest)
-
12496
references!(PredicateBuilder.references(opts)) if Hash === opts
-
-
12496
self.where_values += build_where(opts, rest)
-
12492
self
-
end
-
-
# Allows to specify a HAVING clause. Note that you can't use HAVING
-
# without also specifying a GROUP clause.
-
#
-
# Order.having('SUM(price) > 30').group('user_id')
-
1
def having(opts, *rest)
-
8
opts.blank? ? self : spawn.having!(opts, *rest)
-
end
-
-
# Like #having, but modifies relation in place.
-
1
def having!(opts, *rest)
-
27
references!(PredicateBuilder.references(opts)) if Hash === opts
-
-
27
self.having_values += build_where(opts, rest)
-
27
self
-
end
-
-
# Specifies a limit for the number of records to retrieve.
-
#
-
# User.limit(10) # generated SQL has 'LIMIT 10'
-
#
-
# User.limit(10).limit(20) # generated SQL has 'LIMIT 20'
-
1
def limit(value)
-
5182
spawn.limit!(value)
-
end
-
-
# Like #limit, but modifies relation in place.
-
1
def limit!(value)
-
5375
self.limit_value = value
-
5374
self
-
end
-
-
# Specifies the number of rows to skip before returning rows.
-
#
-
# User.offset(10) # generated SQL has "OFFSET 10"
-
#
-
# Should be used with order.
-
#
-
# User.offset(10).order("name ASC")
-
1
def offset(value)
-
11
spawn.offset!(value)
-
end
-
-
# Like #offset, but modifies relation in place.
-
1
def offset!(value)
-
48
self.offset_value = value
-
48
self
-
end
-
-
# Specifies locking settings (default to +true+). For more information
-
# on locking, please see +ActiveRecord::Locking+.
-
1
def lock(locks = true)
-
7
spawn.lock!(locks)
-
end
-
-
# Like #lock, but modifies relation in place.
-
1
def lock!(locks = true)
-
8
case locks
-
when String, TrueClass, NilClass
-
8
self.lock_value = locks || true
-
else
-
self.lock_value = false
-
end
-
-
8
self
-
end
-
-
# Returns a chainable relation with zero records, specifically an
-
# instance of the <tt>ActiveRecord::NullRelation</tt> class.
-
#
-
# The returned <tt>ActiveRecord::NullRelation</tt> inherits from Relation and implements the
-
# Null Object pattern. It is an object with defined null behavior and always returns an empty
-
# array of records without quering the database.
-
#
-
# Any subsequent condition chained to the returned relation will continue
-
# generating an empty relation and will not fire any query to the database.
-
#
-
# Used in cases where a method or scope could return zero records but the
-
# result needs to be chainable.
-
#
-
# For example:
-
#
-
# @posts = current_user.visible_posts.where(:name => params[:name])
-
# # => the visible_posts method is expected to return a chainable Relation
-
#
-
# def visible_posts
-
# case role
-
# when 'Country Manager'
-
# Post.where(:country => country)
-
# when 'Reviewer'
-
# Post.published
-
# when 'Bad User'
-
# Post.none # => returning [] instead breaks the previous code
-
# end
-
# end
-
#
-
1
def none
-
18
extending(NullRelation)
-
end
-
-
# Like #none, but modifies relation in place.
-
1
def none!
-
93
extending!(NullRelation)
-
end
-
-
# Sets readonly attributes for the returned relation. If value is
-
# true (default), attempting to update a record will result in an error.
-
#
-
# users = User.readonly
-
# users.first.save
-
# => ActiveRecord::ReadOnlyRecord: ActiveRecord::ReadOnlyRecord
-
1
def readonly(value = true)
-
21
spawn.readonly!(value)
-
end
-
-
# Like #readonly, but modifies relation in place.
-
1
def readonly!(value = true)
-
40
self.readonly_value = value
-
40
self
-
end
-
-
# Sets attributes to be used when creating new records from a
-
# relation object.
-
#
-
# users = User.where(name: 'Oscar')
-
# users.new.name # => 'Oscar'
-
#
-
# users = users.create_with(name: 'DHH')
-
# users.new.name # => 'DHH'
-
#
-
# You can pass +nil+ to +create_with+ to reset attributes:
-
#
-
# users = users.create_with(nil)
-
# users.new.name # => 'Oscar'
-
1
def create_with(value)
-
2743
spawn.create_with!(value)
-
end
-
-
# Like #create_with but modifies the relation in place. Raises
-
# +ImmutableRelation+ if the relation has already been loaded.
-
#
-
# users = User.all.create_with!(name: 'Oscar')
-
# users.new.name # => 'Oscar'
-
1
def create_with!(value)
-
2744
self.create_with_value = value ? create_with_value.merge(value) : {}
-
2744
self
-
end
-
-
# Specifies table from which the records will be fetched. For example:
-
#
-
# Topic.select('title').from('posts')
-
# #=> SELECT title FROM posts
-
#
-
# Can accept other relation objects. For example:
-
#
-
# Topic.select('title').from(Topic.approved)
-
# # => SELECT title FROM (SELECT * FROM topics WHERE approved = 't') subquery
-
#
-
# Topic.select('a.title').from(Topic.approved, :a)
-
# # => SELECT a.title FROM (SELECT * FROM topics WHERE approved = 't') a
-
#
-
1
def from(value, subquery_name = nil)
-
17
spawn.from!(value, subquery_name)
-
end
-
-
# Like #from, but modifies relation in place.
-
1
def from!(value, subquery_name = nil)
-
18
self.from_value = [value, subquery_name]
-
18
self
-
end
-
-
# Specifies whether the records should be unique or not. For example:
-
#
-
# User.select(:name)
-
# # => Might return two records with the same name
-
#
-
# User.select(:name).uniq
-
# # => Returns 1 record per unique name
-
#
-
# User.select(:name).uniq.uniq(false)
-
# # => You can also remove the uniqueness
-
1
def uniq(value = true)
-
77
spawn.uniq!(value)
-
end
-
-
# Like #uniq, but modifies relation in place.
-
1
def uniq!(value = true)
-
404
self.uniq_value = value
-
404
self
-
end
-
-
# Used to extend a scope with additional methods, either through
-
# a module or through a block provided.
-
#
-
# The object returned is a relation, which can be further extended.
-
#
-
# === Using a module
-
#
-
# module Pagination
-
# def page(number)
-
# # pagination code goes here
-
# end
-
# end
-
#
-
# scope = Model.all.extending(Pagination)
-
# scope.page(params[:page])
-
#
-
# You can also pass a list of modules:
-
#
-
# scope = Model.all.extending(Pagination, SomethingElse)
-
#
-
# === Using a block
-
#
-
# scope = Model.all.extending do
-
# def page(number)
-
# # pagination code goes here
-
# end
-
# end
-
# scope.page(params[:page])
-
#
-
# You can also use a block and a module list:
-
#
-
# scope = Model.all.extending(Pagination) do
-
# def per_page(number)
-
# # pagination code goes here
-
# end
-
# end
-
1
def extending(*modules, &block)
-
563
if modules.any? || block
-
563
spawn.extending!(*modules, &block)
-
else
-
self
-
end
-
end
-
-
# Like #extending, but modifies relation in place.
-
1
def extending!(*modules, &block)
-
2428
modules << Module.new(&block) if block_given?
-
-
2428
self.extending_values += modules.flatten
-
2427
extend(*extending_values) if extending_values.any?
-
-
2427
self
-
end
-
-
# Reverse the existing order clause on the relation.
-
#
-
# User.order('name ASC').reverse_order # generated SQL has 'ORDER BY name DESC'
-
1
def reverse_order
-
54
spawn.reverse_order!
-
end
-
-
# Like #reverse_order, but modifies relation in place.
-
1
def reverse_order!
-
56
self.reverse_order_value = !reverse_order_value
-
56
self
-
end
-
-
# Returns the Arel object associated with the relation.
-
1
def arel
-
15290
@arel ||= with_default_scope.build_arel
-
end
-
-
# Like #arel, but ignores the default scope of the model.
-
1
def build_arel
-
12698
arel = Arel::SelectManager.new(table.engine, table)
-
-
12698
build_joins(arel, joins_values) unless joins_values.empty?
-
-
12698
collapse_wheres(arel, (where_values - ['']).uniq)
-
-
12706
arel.having(*having_values.uniq.reject{|h| h.blank?}) unless having_values.empty?
-
-
12698
arel.take(connection.sanitize_limit(limit_value)) if limit_value
-
12695
arel.skip(offset_value.to_i) if offset_value
-
-
12766
arel.group(*group_values.uniq.reject{|g| g.blank?}) unless group_values.empty?
-
-
12695
build_order(arel)
-
-
12695
build_select(arel, select_values.uniq)
-
-
12695
arel.distinct(uniq_value)
-
12695
arel.from(build_from) if from_value
-
12695
arel.lock(lock_value) if lock_value
-
-
12695
arel
-
end
-
-
1
private
-
-
1
def custom_join_ast(table, joins)
-
1130
joins = joins.reject { |join| join.blank? }
-
-
1096
return [] if joins.empty?
-
-
26
@implicit_readonly = true
-
-
26
joins.map do |join|
-
29
case join
-
when Array
-
join = Arel.sql(join.join(' ')) if array_of_strings?(join)
-
when String
-
29
join = Arel.sql(join)
-
end
-
29
table.create_string_join(join)
-
end
-
end
-
-
1
def collapse_wheres(arel, wheres)
-
12698
equalities = wheres.grep(Arel::Nodes::Equality)
-
-
12698
arel.where(Arel::Nodes::And.new(equalities)) unless equalities.empty?
-
-
12698
(wheres - equalities).each do |where|
-
644
where = Arel.sql(where) if String === where
-
644
arel.where(Arel::Nodes::Grouping.new(where))
-
end
-
end
-
-
1
def build_where(opts, other = [])
-
12523
case opts
-
when String, Array
-
414
[@klass.send(:sanitize_sql, other.empty? ? opts : ([opts] + other))]
-
when Hash
-
1278
attributes = @klass.send(:expand_hash_conditions_for_aggregates, opts)
-
1278
PredicateBuilder.build_from_hash(klass, attributes, table)
-
else
-
10831
[opts]
-
end
-
end
-
-
1
def build_from
-
22
opts, name = from_value
-
22
case opts
-
when Relation
-
3
name ||= 'subquery'
-
3
opts.arel.as(name.to_s)
-
else
-
19
opts
-
end
-
end
-
-
1
def build_joins(manager, joins)
-
1096
buckets = joins.group_by do |join|
-
1235
case join
-
when String
-
36
:string_join
-
when Hash, Symbol, Array
-
144
:association_join
-
when ActiveRecord::Associations::JoinDependency::JoinAssociation
-
241
:stashed_join
-
when Arel::Nodes::Join
-
814
:join_node
-
else
-
raise 'unknown class: %s' % join.class.name
-
end
-
end
-
-
1096
association_joins = buckets[:association_join] || []
-
1096
stashed_association_joins = buckets[:stashed_join] || []
-
1096
join_nodes = (buckets[:join_node] || []).uniq
-
1096
string_joins = (buckets[:string_join] || []).map { |x|
-
36
x.strip
-
}.uniq
-
-
1096
join_list = join_nodes + custom_join_ast(manager, string_joins)
-
-
1096
join_dependency = ActiveRecord::Associations::JoinDependency.new(
-
@klass,
-
association_joins,
-
join_list
-
)
-
-
1096
join_dependency.graft(*stashed_association_joins)
-
-
1096
@implicit_readonly = true unless association_joins.empty? && stashed_association_joins.empty?
-
-
# FIXME: refactor this to build an AST
-
1096
join_dependency.join_associations.each do |association|
-
387
association.join_to(manager)
-
end
-
-
1096
manager.join_sources.concat join_list
-
-
1096
manager
-
end
-
-
1
def build_select(arel, selects)
-
12695
unless selects.empty?
-
1702
@implicit_readonly = false
-
1702
arel.project(*selects)
-
else
-
10993
arel.project(@klass.arel_table[Arel.star])
-
end
-
end
-
-
1
def reverse_sql_order(order_query)
-
54
order_query = ["#{quoted_table_name}.#{quoted_primary_key} ASC"] if order_query.empty?
-
-
54
order_query.flat_map do |o|
-
59
case o
-
when Arel::Nodes::Ordering
-
5
o.reverse
-
when String
-
52
o.to_s.split(',').collect do |s|
-
54
s.strip!
-
54
s.gsub!(/\sasc\Z/i, ' DESC') || s.gsub!(/\sdesc\Z/i, ' ASC') || s.concat(' DESC')
-
end
-
when Symbol
-
1
{ o => :desc }
-
when Hash
-
1
o.each_with_object({}) do |(field, dir), memo|
-
1
memo[field] = (dir == :asc ? :desc : :asc )
-
end
-
else
-
o
-
end
-
end
-
end
-
-
1
def array_of_strings?(o)
-
o.is_a?(Array) && o.all?{|obj| obj.is_a?(String)}
-
end
-
-
1
def build_order(arel)
-
12695
orders = order_values
-
12695
orders = reverse_sql_order(orders) if reverse_order_value
-
-
12695
orders = orders.uniq.reject(&:blank?).flat_map do |order|
-
2049
case order
-
when Symbol
-
21
table[order].asc
-
when Hash
-
6
order.map { |field, dir| table[field].send(dir) }
-
else
-
2025
order
-
end
-
end
-
-
12695
arel.order(*orders) unless orders.empty?
-
end
-
-
1
def validate_order_args(args)
-
12461
args.select { |a| Hash === a }.each do |h|
-
3
unless (h.values - [:asc, :desc]).empty?
-
1
raise ArgumentError, 'Direction should be :asc or :desc'
-
end
-
end
-
end
-
-
end
-
end
-
1
require 'active_support/core_ext/hash/except'
-
1
require 'active_support/core_ext/hash/slice'
-
1
require 'active_record/relation/merger'
-
-
1
module ActiveRecord
-
1
module SpawnMethods
-
-
# This is overridden by Associations::CollectionProxy
-
1
def spawn #:nodoc:
-
33762
clone
-
end
-
-
# Merges in the conditions from <tt>other</tt>, if <tt>other</tt> is an <tt>ActiveRecord::Relation</tt>.
-
# Returns an array representing the intersection of the resulting records with <tt>other</tt>, if <tt>other</tt> is an array.
-
#
-
# ==== Examples
-
#
-
# Post.where(:published => true).joins(:comments).merge( Comment.where(:spam => false) )
-
# # Performs a single join query with both where conditions.
-
#
-
# recent_posts = Post.order('created_at DESC').first(5)
-
# Post.where(:published => true).merge(recent_posts)
-
# # Returns the intersection of all published posts with the 5 most recently created posts.
-
# # (This is just an example. You'd probably want to do this with a single query!)
-
#
-
# Procs will be evaluated by merge:
-
#
-
# Post.where(published: true).merge(-> { joins(:comments) })
-
# # => Post.where(published: true).joins(:comments)
-
#
-
# This is mainly intended for sharing common conditions between multiple associations.
-
#
-
1
def merge(other)
-
7655
if other.is_a?(Array)
-
to_a & other
-
7655
elsif other
-
7654
spawn.merge!(other)
-
else
-
1
self
-
end
-
end
-
-
# Like #merge, but applies changes in place.
-
1
def merge!(other)
-
12130
if !other.is_a?(Relation) && other.respond_to?(:to_proc)
-
1
instance_exec(&other)
-
else
-
12129
klass = other.is_a?(Hash) ? Relation::HashMerger : Relation::Merger
-
12129
klass.new(self, other).merge
-
end
-
end
-
-
# Removes from the query the condition(s) specified in +skips+.
-
#
-
# Example:
-
#
-
# Post.order('id asc').except(:order) # discards the order condition
-
# Post.where('id > 10').order('id asc').except(:where) # discards the where condition but keeps the order
-
#
-
1
def except(*skips)
-
1784
result = Relation.new(klass, table, values.except(*skips))
-
1784
result.default_scoped = default_scoped
-
1784
result.extend(*extending_values) if extending_values.any?
-
1784
result
-
end
-
-
# Removes any condition from the query other than the one(s) specified in +onlies+.
-
#
-
# Example:
-
#
-
# Post.order('id asc').only(:where) # discards the order condition
-
# Post.order('id asc').only(:where, :order) # uses the specified order
-
#
-
1
def only(*onlies)
-
2
result = Relation.new(klass, table, values.slice(*onlies))
-
2
result.default_scoped = default_scoped
-
2
result.extend(*extending_values) if extending_values.any?
-
2
result
-
end
-
-
end
-
end
-
1
module ActiveRecord
-
###
-
# This class encapsulates a Result returned from calling +exec_query+ on any
-
# database connection adapter. For example:
-
#
-
# x = ActiveRecord::Base.connection.exec_query('SELECT * FROM foo')
-
# x # => #<ActiveRecord::Result:0xdeadbeef>
-
1
class Result
-
1
include Enumerable
-
-
1
attr_reader :columns, :rows, :column_types
-
-
1
def initialize(columns, rows, column_types = {})
-
22080
@columns = columns
-
22080
@rows = rows
-
22080
@hash_rows = nil
-
22080
@column_types = column_types
-
end
-
-
1
def each
-
21690
hash_rows.each { |row| yield row }
-
end
-
-
1
def to_hash
-
hash_rows
-
end
-
-
1
alias :map! :map
-
1
alias :collect! :map
-
-
# Returns true if there are no records.
-
1
def empty?
-
8
rows.empty?
-
end
-
-
1
def to_ary
-
hash_rows
-
end
-
-
1
def [](idx)
-
1
hash_rows[idx]
-
end
-
-
1
def last
-
hash_rows.last
-
end
-
-
1
def initialize_copy(other)
-
39
@columns = columns.dup
-
39
@rows = rows.dup
-
39
@hash_rows = nil
-
end
-
-
1
private
-
1
def hash_rows
-
@hash_rows ||=
-
begin
-
# We freeze the strings to prevent them getting duped when
-
# used as keys in ActiveRecord::Base's @attributes hash
-
66572
columns = @columns.map { |c| c.dup.freeze }
-
8952
@rows.map { |row|
-
12723
Hash[columns.zip(row)]
-
}
-
8956
end
-
end
-
end
-
end
-
1
module ActiveRecord
-
1
module Sanitization
-
1
extend ActiveSupport::Concern
-
-
1
module ClassMethods
-
1
def quote_value(value, column = nil) #:nodoc:
-
27
connection.quote(value,column)
-
end
-
-
# Used to sanitize objects before they're used in an SQL SELECT statement. Delegates to <tt>connection.quote</tt>.
-
1
def sanitize(object) #:nodoc:
-
2
connection.quote(object)
-
end
-
-
1
protected
-
-
# Accepts an array, hash, or string of SQL conditions and sanitizes
-
# them into a valid SQL fragment for a WHERE clause.
-
# ["name='%s' and group_id='%s'", "foo'bar", 4] returns "name='foo''bar' and group_id='4'"
-
# { :name => "foo'bar", :group_id => 4 } returns "name='foo''bar' and group_id='4'"
-
# "name='foo''bar' and group_id='4'" returns "name='foo''bar' and group_id='4'"
-
1
def sanitize_sql_for_conditions(condition, table_name = self.table_name)
-
7332
return nil if condition.blank?
-
-
7332
case condition
-
110
when Array; sanitize_sql_array(condition)
-
when Hash; sanitize_sql_hash_for_conditions(condition, table_name)
-
7222
else condition
-
end
-
end
-
1
alias_method :sanitize_sql, :sanitize_sql_for_conditions
-
-
# Accepts an array, hash, or string of SQL conditions and sanitizes
-
# them into a valid SQL fragment for a SET clause.
-
# { :name => nil, :group_id => 4 } returns "name = NULL , group_id='4'"
-
1
def sanitize_sql_for_assignment(assignments)
-
310
case assignments
-
5
when Array; sanitize_sql_array(assignments)
-
153
when Hash; sanitize_sql_hash_for_assignment(assignments)
-
152
else assignments
-
end
-
end
-
-
# Accepts a hash of SQL conditions and replaces those attributes
-
# that correspond to a +composed_of+ relationship with their expanded
-
# aggregate attribute values.
-
# Given:
-
# class Person < ActiveRecord::Base
-
# composed_of :address, :class_name => "Address",
-
# :mapping => [%w(address_street street), %w(address_city city)]
-
# end
-
# Then:
-
# { :address => Address.new("813 abc st.", "chicago") }
-
# # => { :address_street => "813 abc st.", :address_city => "chicago" }
-
1
def expand_hash_conditions_for_aggregates(attrs)
-
1278
expanded_attrs = {}
-
1278
attrs.each do |attr, value|
-
1348
if aggregation = reflect_on_aggregation(attr.to_sym)
-
32
mapping = aggregation.mapping
-
32
mapping.each do |field_attr, aggregate_attr|
-
60
if mapping.size == 1 && !value.respond_to?(aggregate_attr)
-
2
expanded_attrs[field_attr] = value
-
else
-
58
expanded_attrs[field_attr] = value.send(aggregate_attr)
-
end
-
end
-
else
-
1316
expanded_attrs[attr] = value
-
end
-
end
-
1278
expanded_attrs
-
end
-
-
# Sanitizes a hash of attribute/value pairs into SQL conditions for a WHERE clause.
-
# { :name => "foo'bar", :group_id => 4 }
-
# # => "name='foo''bar' and group_id= 4"
-
# { :status => nil, :group_id => [1,2,3] }
-
# # => "status IS NULL and group_id IN (1,2,3)"
-
# { :age => 13..18 }
-
# # => "age BETWEEN 13 AND 18"
-
# { 'other_records.id' => 7 }
-
# # => "`other_records`.`id` = 7"
-
# { :other_records => { :id => 7 } }
-
# # => "`other_records`.`id` = 7"
-
# And for value objects on a composed_of relationship:
-
# { :address => Address.new("123 abc st.", "chicago") }
-
# # => "address_street='123 abc st.' and address_city='chicago'"
-
1
def sanitize_sql_hash_for_conditions(attrs, default_table_name = self.table_name)
-
attrs = expand_hash_conditions_for_aggregates(attrs)
-
-
table = Arel::Table.new(table_name, arel_engine).alias(default_table_name)
-
PredicateBuilder.build_from_hash(self.class, attrs, table).map { |b|
-
connection.visitor.accept b
-
}.join(' AND ')
-
end
-
1
alias_method :sanitize_sql_hash, :sanitize_sql_hash_for_conditions
-
-
# Sanitizes a hash of attribute/value pairs into SQL conditions for a SET clause.
-
# { :status => nil, :group_id => 1 }
-
# # => "status = NULL , group_id = 1"
-
1
def sanitize_sql_hash_for_assignment(attrs)
-
153
attrs.map do |attr, value|
-
160
"#{connection.quote_column_name(attr)} = #{quote_bound_value(value)}"
-
end.join(', ')
-
end
-
-
# Accepts an array of conditions. The array has each value
-
# sanitized and interpolated into the SQL statement.
-
# ["name='%s' and group_id='%s'", "foo'bar", 4] returns "name='foo''bar' and group_id='4'"
-
1
def sanitize_sql_array(ary)
-
123
statement, *values = ary
-
123
if values.first.is_a?(Hash) && statement =~ /:\w+/
-
7
replace_named_bind_variables(statement, values.first)
-
116
elsif statement.include?('?')
-
102
replace_bind_variables(statement, values)
-
13
elsif statement.blank?
-
statement
-
else
-
25
statement % values.collect { |value| connection.quote_string(value.to_s) }
-
end
-
end
-
-
1
alias_method :sanitize_conditions, :sanitize_sql
-
-
1
def replace_bind_variables(statement, values) #:nodoc:
-
121
raise_if_bind_arity_mismatch(statement, statement.count('?'), values.size)
-
116
bound = values.dup
-
116
c = connection
-
233
statement.gsub('?') { quote_bound_value(bound.shift, c) }
-
end
-
-
1
def replace_named_bind_variables(statement, bind_vars) #:nodoc:
-
16
statement.gsub(/(:?):([a-zA-Z]\w*)/) do
-
20
if $1 == ':' # skip postgresql casts
-
4
$& # return the whole match
-
elsif bind_vars.include?(match = $2.to_sym)
-
16
quote_bound_value(bind_vars[match])
-
else
-
raise PreparedStatementInvalid, "missing value for :#{match} in #{statement}"
-
end
-
end
-
end
-
-
1
def quote_bound_value(value, c = connection) #:nodoc:
-
293
if value.respond_to?(:map) && !value.acts_like?(:string)
-
18
if value.respond_to?(:empty?) && value.empty?
-
5
c.quote(nil)
-
else
-
46
value.map { |v| c.quote(v) }.join(',')
-
end
-
else
-
275
c.quote(value)
-
end
-
end
-
-
1
def raise_if_bind_arity_mismatch(statement, expected, provided) #:nodoc:
-
121
unless expected == provided
-
5
raise PreparedStatementInvalid, "wrong number of bind variables (#{provided} for #{expected}) in: #{statement}"
-
end
-
end
-
end
-
-
# TODO: Deprecate this
-
1
def quoted_id
-
3
self.class.quote_value(id, column_for_attribute(self.class.primary_key))
-
end
-
end
-
end
-
-
1
module ActiveRecord
-
# = Active Record Schema
-
#
-
# Allows programmers to programmatically define a schema in a portable
-
# DSL. This means you can define tables, indexes, etc. without using SQL
-
# directly, so your applications can more easily support multiple
-
# databases.
-
#
-
# Usage:
-
#
-
# ActiveRecord::Schema.define do
-
# create_table :authors do |t|
-
# t.string :name, null: false
-
# end
-
#
-
# add_index :authors, :name, :unique
-
#
-
# create_table :posts do |t|
-
# t.integer :author_id, null: false
-
# t.string :subject
-
# t.text :body
-
# t.boolean :private, default: false
-
# end
-
#
-
# add_index :posts, :author_id
-
# end
-
#
-
# ActiveRecord::Schema is only supported by database adapters that also
-
# support migrations, the two features being very similar.
-
1
class Schema < Migration
-
1
def migrations_paths
-
2
ActiveRecord::Migrator.migrations_paths
-
end
-
-
1
def define(info, &block)
-
5
instance_eval(&block)
-
-
4
unless info[:version].blank?
-
2
initialize_schema_migrations_table
-
2
assume_migrated_upto_version(info[:version], migrations_paths)
-
end
-
end
-
-
# Eval the given block. All methods available to the current connection
-
# adapter are available within the block, so you can easily use the
-
# database definition DSL to build up your schema (+create_table+,
-
# +add_index+, etc.).
-
#
-
# The +info+ hash is optional, and if given is used to define metadata
-
# about the current schema (currently, only the schema's version):
-
#
-
# ActiveRecord::Schema.define(version: 20380119000001) do
-
# ...
-
# end
-
1
def self.define(info={}, &block)
-
5
new.define(info, &block)
-
end
-
end
-
end
-
1
require 'stringio'
-
1
require 'active_support/core_ext/big_decimal'
-
-
1
module ActiveRecord
-
# = Active Record Schema Dumper
-
#
-
# This class is used to dump the database schema for some connection to some
-
# output format (i.e., ActiveRecord::Schema).
-
1
class SchemaDumper #:nodoc:
-
1
private_class_method :new
-
-
##
-
# :singleton-method:
-
# A list of tables which should not be dumped to the schema.
-
# Acceptable values are strings as well as regexp.
-
# This setting is only used if ActiveRecord::Base.schema_format == :ruby
-
1
cattr_accessor :ignore_tables
-
1
@@ignore_tables = []
-
-
1
def self.dump(connection=ActiveRecord::Base.connection, stream=STDOUT)
-
29
new(connection).dump(stream)
-
28
stream
-
end
-
-
1
def dump(stream)
-
29
header(stream)
-
29
tables(stream)
-
28
trailer(stream)
-
28
stream
-
end
-
-
1
private
-
-
1
def initialize(connection)
-
29
@connection = connection
-
29
@types = @connection.native_database_types
-
29
@version = Migrator::current_version rescue nil
-
end
-
-
1
def header(stream)
-
29
define_params = @version ? "version: #{@version}" : ""
-
-
29
if stream.respond_to?(:external_encoding) && stream.external_encoding
-
29
stream.puts "# encoding: #{stream.external_encoding.name}"
-
end
-
-
29
stream.puts <<HEADER
-
# This file is auto-generated from the current state of the database. Instead
-
# of editing this file, please use the migrations feature of Active Record to
-
# incrementally modify your database, and then regenerate this schema definition.
-
#
-
# Note that this schema.rb definition is the authoritative source for your
-
# database schema. If you need to create the application database on another
-
# system, you should be using db:schema:load, not running all the migrations
-
# from scratch. The latter is a flawed and unsustainable approach (the more migrations
-
# you'll amass, the slower it'll run and the greater likelihood for issues).
-
#
-
# It's strongly recommended that you check this file into your version control system.
-
-
ActiveRecord::Schema.define(#{define_params}) do
-
-
HEADER
-
end
-
-
1
def trailer(stream)
-
28
stream.puts "end"
-
end
-
-
1
def tables(stream)
-
29
@connection.tables.sort.each do |tbl|
-
4118
next if ['schema_migrations', ignore_tables].flatten.any? do |ignored|
-
4849
case ignored
-
4264
when String; remove_prefix_and_suffix(tbl) == ignored
-
584
when Regexp; remove_prefix_and_suffix(tbl) =~ ignored
-
else
-
1
raise StandardError, 'ActiveRecord::SchemaDumper.ignore_tables accepts an array of String and / or Regexp values.'
-
end
-
end
-
3657
table(tbl, stream)
-
end
-
end
-
-
1
def table(table, stream)
-
3657
columns = @connection.columns(table)
-
3657
begin
-
3657
tbl = StringIO.new
-
-
# first dump primary key column
-
3657
if @connection.respond_to?(:pk_and_sequence_for)
-
3657
pk, _ = @connection.pk_and_sequence_for(table)
-
elsif @connection.respond_to?(:primary_key)
-
pk = @connection.primary_key(table)
-
end
-
-
3657
tbl.print " create_table #{remove_prefix_and_suffix(table).inspect}"
-
7989
if columns.detect { |c| c.name == pk }
-
3182
if pk != 'id'
-
175
tbl.print %Q(, primary_key: "#{pk}")
-
end
-
else
-
475
tbl.print ", id: false"
-
end
-
3657
tbl.print ", force: true"
-
3657
tbl.puts " do |t|"
-
-
# then dump all non-primary key columns
-
3657
column_specs = columns.map do |column|
-
13104
raise StandardError, "Unknown type '#{column.sql_type}' for column '#{column.name}'" if @types[column.type].nil?
-
13104
next if column.name == pk
-
9922
@connection.column_spec(column, @types)
-
end.compact
-
-
# find all migration keys used in this table
-
3657
keys = @connection.migration_keys
-
-
# figure out the lengths for each column based on above keys
-
3657
lengths = keys.map { |key|
-
25599
column_specs.map { |spec|
-
69454
spec[key] ? spec[key].length + 2 : 0
-
}.max
-
}
-
-
# the string we're going to sprintf our values against, with standardized column widths
-
29256
format_string = lengths.map{ |len| "%-#{len}s" }
-
-
# find the max length for the 'type' column, which is special
-
13579
type_length = column_specs.map{ |column| column[:type].length }.max
-
-
# add column type definition to our format string
-
3657
format_string.unshift " t.%-#{type_length}s "
-
-
3657
format_string *= ''
-
-
3657
column_specs.each do |colspec|
-
79376
values = keys.zip(lengths).map{ |key, len| colspec.key?(key) ? colspec[key] + ", " : " " * len }
-
9922
values.unshift colspec[:type]
-
9922
tbl.print((format_string % values).gsub(/,\s*$/, ''))
-
9922
tbl.puts
-
end
-
-
3657
tbl.puts " end"
-
3657
tbl.puts
-
-
3657
indexes(table, tbl)
-
-
3657
tbl.rewind
-
3657
stream.print tbl.read
-
rescue => e
-
stream.puts "# Could not dump table #{table.inspect} because of following #{e.class}"
-
stream.puts "# #{e.message}"
-
stream.puts
-
end
-
-
3657
stream
-
end
-
-
1
def indexes(table, stream)
-
3657
if (indexes = @connection.indexes(table)).any?
-
76
add_index_statements = indexes.map do |index|
-
101
statement_parts = [
-
101
('add_index ' + remove_prefix_and_suffix(index.table).inspect),
-
index.columns.inspect,
-
101
('name: ' + index.name.inspect),
-
]
-
101
statement_parts << 'unique: true' if index.unique
-
-
101
index_lengths = (index.lengths || []).compact
-
101
statement_parts << ('length: ' + Hash[index.columns.zip(index.lengths)].inspect) unless index_lengths.empty?
-
-
101
index_orders = (index.orders || {})
-
101
statement_parts << ('order: ' + index.orders.inspect) unless index_orders.empty?
-
-
101
statement_parts << ('where: ' + index.where.inspect) if index.where
-
-
101
' ' + statement_parts.join(', ')
-
end
-
-
76
stream.puts add_index_statements.sort.join("\n")
-
76
stream.puts
-
end
-
end
-
-
1
def remove_prefix_and_suffix(table)
-
8606
table.gsub(/^(#{ActiveRecord::Base.table_name_prefix})(.+)(#{ActiveRecord::Base.table_name_suffix})$/, "\\2")
-
end
-
end
-
end
-
1
require 'active_record/scoping/default'
-
1
require 'active_record/scoping/named'
-
1
require 'active_record/base'
-
-
1
module ActiveRecord
-
1
class SchemaMigration < ActiveRecord::Base
-
-
1
def self.table_name
-
342
"#{Base.table_name_prefix}schema_migrations#{Base.table_name_suffix}"
-
end
-
-
1
def self.index_name
-
4
"#{Base.table_name_prefix}unique_schema_migrations#{Base.table_name_suffix}"
-
end
-
-
1
def self.create_table
-
135
unless connection.table_exists?(table_name)
-
3
connection.create_table(table_name, :id => false) do |t|
-
3
t.column :version, :string, :null => false
-
end
-
3
connection.add_index table_name, :version, :unique => true, :name => index_name
-
end
-
end
-
-
1
def self.drop_table
-
1
if connection.table_exists?(table_name)
-
1
connection.remove_index table_name, :name => index_name
-
1
connection.drop_table(table_name)
-
end
-
end
-
-
1
def version
-
141
super.to_i
-
end
-
end
-
end
-
-
1
module ActiveRecord
-
1
module Scoping
-
1
extend ActiveSupport::Concern
-
-
1
included do
-
1
include Default
-
1
include Named
-
end
-
-
1
module ClassMethods
-
1
def current_scope #:nodoc:
-
27226
Thread.current["#{self}_current_scope"]
-
end
-
-
1
def current_scope=(scope) #:nodoc:
-
18652
Thread.current["#{self}_current_scope"] = scope
-
end
-
end
-
-
1
def populate_with_current_scope_attributes
-
2991
return unless self.class.scope_attributes?
-
-
158
self.class.scope_attributes.each do |att,value|
-
189
send("#{att}=", value) if respond_to?("#{att}=")
-
end
-
end
-
-
end
-
end
-
1
require 'active_support/core_ext/array'
-
1
require 'active_support/core_ext/hash/except'
-
1
require 'active_support/core_ext/kernel/singleton_class'
-
-
1
module ActiveRecord
-
# = Active Record \Named \Scopes
-
1
module Scoping
-
1
module Named
-
1
extend ActiveSupport::Concern
-
-
1
module ClassMethods
-
# Returns an <tt>ActiveRecord::Relation</tt> scope object.
-
#
-
# posts = Post.all
-
# posts.size # Fires "select count(*) from posts" and returns the count
-
# posts.each {|p| puts p.name } # Fires "select * from posts" and loads post objects
-
#
-
# fruits = Fruit.all
-
# fruits = fruits.where(color: 'red') if options[:red_only]
-
# fruits = fruits.limit(10) if limited?
-
#
-
# You can define a scope that applies to all finders using
-
# <tt>ActiveRecord::Base.default_scope</tt>.
-
1
def all
-
13674
if current_scope
-
975
current_scope.clone
-
else
-
12699
scope = relation
-
12699
scope.default_scoped = true
-
12699
scope
-
end
-
end
-
-
# Collects attributes from scopes that should be applied when creating
-
# an AR instance for the particular class this is called on.
-
1
def scope_attributes # :nodoc:
-
158
if current_scope
-
103
current_scope.scope_for_create
-
else
-
55
scope = relation
-
55
scope.default_scoped = true
-
55
scope.scope_for_create
-
end
-
end
-
-
# Are there default attributes associated with this scope?
-
1
def scope_attributes? # :nodoc:
-
2991
current_scope || default_scopes.any?
-
end
-
-
# Adds a class method for retrieving and querying objects. A \scope
-
# represents a narrowing of a database query, such as
-
# <tt>where(color: :red).select('shirts.*').includes(:washing_instructions)</tt>.
-
#
-
# class Shirt < ActiveRecord::Base
-
# scope :red, -> { where(color: 'red') }
-
# scope :dry_clean_only, -> { joins(:washing_instructions).where('washing_instructions.dry_clean_only = ?', true) }
-
# end
-
#
-
# The above calls to +scope+ define class methods <tt>Shirt.red</tt> and
-
# <tt>Shirt.dry_clean_only</tt>. <tt>Shirt.red</tt>, in effect,
-
# represents the query <tt>Shirt.where(color: 'red')</tt>.
-
#
-
# You should always pass a callable object to the scopes defined
-
# with +scope+. This ensures that the scope is re-evaluated each
-
# time it is called.
-
#
-
# Note that this is simply 'syntactic sugar' for defining an actual
-
# class method:
-
#
-
# class Shirt < ActiveRecord::Base
-
# def self.red
-
# where(color: 'red')
-
# end
-
# end
-
#
-
# Unlike <tt>Shirt.find(...)</tt>, however, the object returned by
-
# <tt>Shirt.red</tt> is not an Array; it resembles the association object
-
# constructed by a +has_many+ declaration. For instance, you can invoke
-
# <tt>Shirt.red.first</tt>, <tt>Shirt.red.count</tt>,
-
# <tt>Shirt.red.where(size: 'small')</tt>. Also, just as with the
-
# association objects, named \scopes act like an Array, implementing
-
# Enumerable; <tt>Shirt.red.each(&block)</tt>, <tt>Shirt.red.first</tt>,
-
# and <tt>Shirt.red.inject(memo, &block)</tt> all behave as if
-
# <tt>Shirt.red</tt> really was an Array.
-
#
-
# These named \scopes are composable. For instance,
-
# <tt>Shirt.red.dry_clean_only</tt> will produce all shirts that are
-
# both red and dry clean only. Nested finds and calculations also work
-
# with these compositions: <tt>Shirt.red.dry_clean_only.count</tt>
-
# returns the number of garments for which these criteria obtain.
-
# Similarly with <tt>Shirt.red.dry_clean_only.average(:thread_count)</tt>.
-
#
-
# All scopes are available as class methods on the ActiveRecord::Base
-
# descendant upon which the \scopes were defined. But they are also
-
# available to +has_many+ associations. If,
-
#
-
# class Person < ActiveRecord::Base
-
# has_many :shirts
-
# end
-
#
-
# then <tt>elton.shirts.red.dry_clean_only</tt> will return all of
-
# Elton's red, dry clean only shirts.
-
#
-
# \Named scopes can also have extensions, just as with +has_many+
-
# declarations:
-
#
-
# class Shirt < ActiveRecord::Base
-
# scope :red, -> { where(color: 'red') } do
-
# def dom_id
-
# 'red_shirts'
-
# end
-
# end
-
# end
-
#
-
# Scopes can also be used while creating/building a record.
-
#
-
# class Article < ActiveRecord::Base
-
# scope :published, -> { where(published: true) }
-
# end
-
#
-
# Article.published.new.published # => true
-
# Article.published.create.published # => true
-
#
-
# \Class methods on your model are automatically available
-
# on scopes. Assuming the following setup:
-
#
-
# class Article < ActiveRecord::Base
-
# scope :published, -> { where(published: true) }
-
# scope :featured, -> { where(featured: true) }
-
#
-
# def self.latest_article
-
# order('published_at desc').first
-
# end
-
#
-
# def self.titles
-
# map(&:title)
-
# end
-
#
-
# end
-
#
-
# We are able to call the methods like this:
-
#
-
# Article.published.featured.latest_article
-
# Article.featured.titles
-
-
1
def scope(name, body, &block)
-
43
extension = Module.new(&block) if block
-
-
# Check body.is_a?(Relation) to prevent the relation actually being
-
# loaded by respond_to?
-
43
if body.is_a?(Relation) || !body.respond_to?(:call)
-
1
ActiveSupport::Deprecation.warn(
-
"Using #scope without passing a callable object is deprecated. For " \
-
"example `scope :red, where(color: 'red')` should be changed to " \
-
"`scope :red, -> { where(color: 'red') }`. There are numerous gotchas " \
-
"in the former usage and it makes the implementation more complicated " \
-
"and buggy. (If you prefer, you can just define a class method named " \
-
"`self.red`.)"
-
)
-
end
-
-
43
singleton_class.send(:define_method, name) do |*args|
-
317
options = body.respond_to?(:call) ? unscoped { body.call(*args) } : body
-
159
relation = all.merge(options)
-
-
159
extension ? relation.extending(extension) : relation
-
end
-
end
-
end
-
end
-
end
-
end
-
1
module ActiveRecord #:nodoc:
-
# = Active Record Serialization
-
1
module Serialization
-
1
extend ActiveSupport::Concern
-
1
include ActiveModel::Serializers::JSON
-
-
1
included do
-
1
self.include_root_in_json = true
-
end
-
-
1
def serializable_hash(options = nil)
-
199
options = options.try(:clone) || {}
-
-
225
options[:except] = Array(options[:except]).map { |n| n.to_s }
-
199
options[:except] |= Array(self.class.inheritance_column)
-
-
199
super(options)
-
end
-
end
-
end
-
-
1
require 'active_record/serializers/xml_serializer'
-
1
require 'active_support/core_ext/hash/conversions'
-
-
1
module ActiveRecord #:nodoc:
-
1
module Serialization
-
1
include ActiveModel::Serializers::Xml
-
-
# Builds an XML document to represent the model. Some configuration is
-
# available through +options+. However more complicated cases should
-
# override ActiveRecord::Base#to_xml.
-
#
-
# By default the generated XML document will include the processing
-
# instruction and all the object's attributes. For example:
-
#
-
# <?xml version="1.0" encoding="UTF-8"?>
-
# <topic>
-
# <title>The First Topic</title>
-
# <author-name>David</author-name>
-
# <id type="integer">1</id>
-
# <approved type="boolean">false</approved>
-
# <replies-count type="integer">0</replies-count>
-
# <bonus-time type="dateTime">2000-01-01T08:28:00+12:00</bonus-time>
-
# <written-on type="dateTime">2003-07-16T09:28:00+1200</written-on>
-
# <content>Have a nice day</content>
-
# <author-email-address>david@loudthinking.com</author-email-address>
-
# <parent-id></parent-id>
-
# <last-read type="date">2004-04-15</last-read>
-
# </topic>
-
#
-
# This behavior can be controlled with <tt>:only</tt>, <tt>:except</tt>,
-
# <tt>:skip_instruct</tt>, <tt>:skip_types</tt>, <tt>:dasherize</tt> and <tt>:camelize</tt> .
-
# The <tt>:only</tt> and <tt>:except</tt> options are the same as for the
-
# +attributes+ method. The default is to dasherize all column names, but you
-
# can disable this setting <tt>:dasherize</tt> to +false+. Setting <tt>:camelize</tt>
-
# to +true+ will camelize all column names - this also overrides <tt>:dasherize</tt>.
-
# To not have the column type included in the XML output set <tt>:skip_types</tt> to +true+.
-
#
-
# For instance:
-
#
-
# topic.to_xml(:skip_instruct => true, :except => [ :id, :bonus_time, :written_on, :replies_count ])
-
#
-
# <topic>
-
# <title>The First Topic</title>
-
# <author-name>David</author-name>
-
# <approved type="boolean">false</approved>
-
# <content>Have a nice day</content>
-
# <author-email-address>david@loudthinking.com</author-email-address>
-
# <parent-id></parent-id>
-
# <last-read type="date">2004-04-15</last-read>
-
# </topic>
-
#
-
# To include first level associations use <tt>:include</tt>:
-
#
-
# firm.to_xml :include => [ :account, :clients ]
-
#
-
# <?xml version="1.0" encoding="UTF-8"?>
-
# <firm>
-
# <id type="integer">1</id>
-
# <rating type="integer">1</rating>
-
# <name>37signals</name>
-
# <clients type="array">
-
# <client>
-
# <rating type="integer">1</rating>
-
# <name>Summit</name>
-
# </client>
-
# <client>
-
# <rating type="integer">1</rating>
-
# <name>Microsoft</name>
-
# </client>
-
# </clients>
-
# <account>
-
# <id type="integer">1</id>
-
# <credit-limit type="integer">50</credit-limit>
-
# </account>
-
# </firm>
-
#
-
# Additionally, the record being serialized will be passed to a Proc's second
-
# parameter. This allows for ad hoc additions to the resultant document that
-
# incorporate the context of the record being serialized. And by leveraging the
-
# closure created by a Proc, to_xml can be used to add elements that normally fall
-
# outside of the scope of the model -- for example, generating and appending URLs
-
# associated with models.
-
#
-
# proc = Proc.new { |options, record| options[:builder].tag!('name-reverse', record.name.reverse) }
-
# firm.to_xml :procs => [ proc ]
-
#
-
# <firm>
-
# # ... normal attributes as shown above ...
-
# <name-reverse>slangis73</name-reverse>
-
# </firm>
-
#
-
# To include deeper levels of associations pass a hash like this:
-
#
-
# firm.to_xml :include => {:account => {}, :clients => {:include => :address}}
-
# <?xml version="1.0" encoding="UTF-8"?>
-
# <firm>
-
# <id type="integer">1</id>
-
# <rating type="integer">1</rating>
-
# <name>37signals</name>
-
# <clients type="array">
-
# <client>
-
# <rating type="integer">1</rating>
-
# <name>Summit</name>
-
# <address>
-
# ...
-
# </address>
-
# </client>
-
# <client>
-
# <rating type="integer">1</rating>
-
# <name>Microsoft</name>
-
# <address>
-
# ...
-
# </address>
-
# </client>
-
# </clients>
-
# <account>
-
# <id type="integer">1</id>
-
# <credit-limit type="integer">50</credit-limit>
-
# </account>
-
# </firm>
-
#
-
# To include any methods on the model being called use <tt>:methods</tt>:
-
#
-
# firm.to_xml :methods => [ :calculated_earnings, :real_earnings ]
-
#
-
# <firm>
-
# # ... normal attributes as shown above ...
-
# <calculated-earnings>100000000000000000</calculated-earnings>
-
# <real-earnings>5</real-earnings>
-
# </firm>
-
#
-
# To call any additional Procs use <tt>:procs</tt>. The Procs are passed a
-
# modified version of the options hash that was given to +to_xml+:
-
#
-
# proc = Proc.new { |options| options[:builder].tag!('abc', 'def') }
-
# firm.to_xml :procs => [ proc ]
-
#
-
# <firm>
-
# # ... normal attributes as shown above ...
-
# <abc>def</abc>
-
# </firm>
-
#
-
# Alternatively, you can yield the builder object as part of the +to_xml+ call:
-
#
-
# firm.to_xml do |xml|
-
# xml.creator do
-
# xml.first_name "David"
-
# xml.last_name "Heinemeier Hansson"
-
# end
-
# end
-
#
-
# <firm>
-
# # ... normal attributes as shown above ...
-
# <creator>
-
# <first_name>David</first_name>
-
# <last_name>Heinemeier Hansson</last_name>
-
# </creator>
-
# </firm>
-
#
-
# As noted above, you may override +to_xml+ in your ActiveRecord::Base
-
# subclasses to have complete control about what's generated. The general
-
# form of doing this is:
-
#
-
# class IHaveMyOwnXML < ActiveRecord::Base
-
# def to_xml(options = {})
-
# require 'builder'
-
# options[:indent] ||= 2
-
# xml = options[:builder] ||= ::Builder::XmlMarkup.new(:indent => options[:indent])
-
# xml.instruct! unless options[:skip_instruct]
-
# xml.level_one do
-
# xml.tag!(:second_level, 'content')
-
# end
-
# end
-
# end
-
1
def to_xml(options = {}, &block)
-
117
XmlSerializer.new(self, options).serialize(&block)
-
end
-
end
-
-
1
class XmlSerializer < ActiveModel::Serializers::Xml::Serializer #:nodoc:
-
1
class Attribute < ActiveModel::Serializers::Xml::Serializer::Attribute #:nodoc:
-
1
def compute_type
-
1001
klass = @serializable.class
-
1001
type = if klass.serialized_attributes.key?(name)
-
37
super
-
elsif klass.columns_hash.key?(name)
-
934
klass.columns_hash[name].type
-
else
-
30
NilClass
-
end
-
-
{ :text => :string,
-
1001
:time => :datetime }[type] || type
-
end
-
1
protected :compute_type
-
end
-
end
-
end
-
1
require 'active_support/core_ext/hash/indifferent_access'
-
-
1
module ActiveRecord
-
# Store gives you a thin wrapper around serialize for the purpose of storing hashes in a single column.
-
# It's like a simple key/value store baked into your record when you don't care about being able to
-
# query that store outside the context of a single record.
-
#
-
# You can then declare accessors to this store that are then accessible just like any other attribute
-
# of the model. This is very helpful for easily exposing store keys to a form or elsewhere that's
-
# already built around just accessing attributes on the model.
-
#
-
# Make sure that you declare the database column used for the serialized store as a text, so there's
-
# plenty of room.
-
#
-
# You can set custom coder to encode/decode your serialized attributes to/from different formats.
-
# JSON, YAML, Marshal are supported out of the box. Generally it can be any wrapper that provides +load+ and +dump+.
-
#
-
# Examples:
-
#
-
# class User < ActiveRecord::Base
-
# store :settings, accessors: [ :color, :homepage ], coder: JSON
-
# end
-
#
-
# u = User.new(color: 'black', homepage: '37signals.com')
-
# u.color # Accessor stored attribute
-
# u.settings[:country] = 'Denmark' # Any attribute, even if not specified with an accessor
-
#
-
# # There is no difference between strings and symbols for accessing custom attributes
-
# u.settings[:country] # => 'Denmark'
-
# u.settings['country'] # => 'Denmark'
-
#
-
# # Add additional accessors to an existing store through store_accessor
-
# class SuperUser < User
-
# store_accessor :settings, :privileges, :servants
-
# end
-
#
-
# The stored attribute names can be retrieved using +stored_attributes+.
-
#
-
# User.stored_attributes[:settings] # [:color, :homepage]
-
#
-
# == Overwriting default accessors
-
#
-
# All stored values are automatically available through accessors on the Active Record
-
# object, but sometimes you want to specialize this behavior. This can be done by overwriting
-
# the default accessors (using the same name as the attribute) and calling
-
# <tt>read_store_attribute(store_attribute_name, attr_name)</tt> and
-
# <tt>write_store_attribute(store_attribute_name, attr_name, value)</tt> to actually
-
# change things.
-
#
-
# class Song < ActiveRecord::Base
-
# # Uses a stored integer to hold the volume adjustment of the song
-
# store :settings, accessors: [:volume_adjustment]
-
#
-
# def volume_adjustment=(decibels)
-
# write_store_attribute(:settings, :volume_adjustment, decibels.to_i)
-
# end
-
#
-
# def volume_adjustment
-
# read_store_attribute(:settings, :volume_adjustment).to_i
-
# end
-
# end
-
1
module Store
-
1
extend ActiveSupport::Concern
-
-
1
included do
-
1
class_attribute :stored_attributes, instance_accessor: false
-
1
self.stored_attributes = {}
-
end
-
-
1
module ClassMethods
-
1
def store(store_attribute, options = {})
-
4
serialize store_attribute, IndifferentCoder.new(options[:coder])
-
4
store_accessor(store_attribute, options[:accessors]) if options.has_key? :accessors
-
end
-
-
1
def store_accessor(store_attribute, *keys)
-
5
keys = keys.flatten
-
5
keys.each do |key|
-
7
define_method("#{key}=") do |value|
-
97
write_store_attribute(store_attribute, key, value)
-
end
-
-
7
define_method(key) do
-
13
read_store_attribute(store_attribute, key)
-
end
-
end
-
-
5
self.stored_attributes[store_attribute] ||= []
-
5
self.stored_attributes[store_attribute] |= keys
-
end
-
end
-
-
1
protected
-
1
def read_store_attribute(store_attribute, key)
-
14
attribute = initialize_store_attribute(store_attribute)
-
14
attribute[key]
-
end
-
-
1
def write_store_attribute(store_attribute, key, value)
-
98
attribute = initialize_store_attribute(store_attribute)
-
98
if value != attribute[key]
-
97
send :"#{store_attribute}_will_change!"
-
97
attribute[key] = value
-
end
-
end
-
-
1
private
-
1
def initialize_store_attribute(store_attribute)
-
112
attribute = send(store_attribute)
-
112
unless attribute.is_a?(HashWithIndifferentAccess)
-
1
attribute = IndifferentCoder.as_indifferent_hash(attribute)
-
1
send :"#{store_attribute}=", attribute
-
end
-
112
attribute
-
end
-
-
1
class IndifferentCoder # :nodoc:
-
1
def initialize(coder_or_class_name)
-
4
@coder =
-
if coder_or_class_name.respond_to?(:load) && coder_or_class_name.respond_to?(:dump)
-
2
coder_or_class_name
-
else
-
2
ActiveRecord::Coders::YAMLColumn.new(coder_or_class_name || Object)
-
end
-
end
-
-
1
def dump(obj)
-
92
@coder.dump self.class.as_indifferent_hash(obj)
-
end
-
-
1
def load(yaml)
-
172
self.class.as_indifferent_hash @coder.load(yaml)
-
end
-
-
1
def self.as_indifferent_hash(obj)
-
265
case obj
-
when HashWithIndifferentAccess
-
135
obj
-
when Hash
-
44
obj.with_indifferent_access
-
else
-
86
HashWithIndifferentAccess.new
-
end
-
end
-
end
-
end
-
end
-
1
module ActiveRecord
-
1
module Tasks # :nodoc:
-
1
class MySQLDatabaseTasks # :nodoc:
-
-
1
DEFAULT_CHARSET = ENV['CHARSET'] || 'utf8'
-
1
DEFAULT_COLLATION = ENV['COLLATION'] || 'utf8_unicode_ci'
-
1
ACCESS_DENIED_ERROR = 1045
-
-
1
delegate :connection, :establish_connection, to: ActiveRecord::Base
-
-
1
def initialize(configuration)
-
15
@configuration = configuration
-
end
-
-
1
def create
-
6
establish_connection configuration_without_database
-
6
connection.create_database configuration['database'], creation_options
-
6
establish_connection configuration
-
rescue error_class => error
-
raise error unless error.errno == ACCESS_DENIED_ERROR
-
-
$stdout.print error.error
-
establish_connection root_configuration_without_database
-
connection.create_database configuration['database'], creation_options
-
connection.execute grant_statement.gsub(/\s+/, ' ').strip
-
establish_connection configuration
-
rescue error_class => error
-
$stderr.puts error.error
-
$stderr.puts "Couldn't create database for #{configuration.inspect}, #{creation_options.inspect}"
-
$stderr.puts "(If you set the charset manually, make sure you have a matching collation)" if configuration['encoding']
-
end
-
-
1
def drop
-
2
establish_connection configuration
-
2
connection.drop_database configuration['database']
-
end
-
-
1
def purge
-
3
establish_connection :test
-
3
connection.recreate_database configuration['database'], creation_options
-
end
-
-
1
def charset
-
1
connection.charset
-
end
-
-
1
def collation
-
1
connection.collation
-
end
-
-
1
def structure_dump(filename)
-
1
args = prepare_command_options('mysqldump')
-
1
args.concat(["--result-file", "#{filename}"])
-
1
args.concat(["--no-data"])
-
1
args.concat(["#{configuration['database']}"])
-
1
Kernel.system(*args)
-
end
-
-
1
def structure_load(filename)
-
1
args = prepare_command_options('mysql')
-
1
args.concat(['--execute', %{SET FOREIGN_KEY_CHECKS = 0; SOURCE #{filename}; SET FOREIGN_KEY_CHECKS = 1}])
-
1
args.concat(["--database", "#{configuration['database']}"])
-
1
Kernel.system(*args)
-
end
-
-
1
private
-
-
1
def configuration
-
58
@configuration
-
end
-
-
1
def configuration_without_database
-
6
configuration.merge('database' => nil)
-
end
-
-
1
def creation_options
-
9
Hash.new.tap do |options|
-
9
options[:charset] = configuration['encoding'] if configuration.include? 'encoding'
-
9
options[:collation] = configuration['collation'] if configuration.include? 'collation'
-
-
# Set default charset only when collation isn't set.
-
9
options[:charset] ||= DEFAULT_CHARSET unless options[:collation]
-
-
# Set default collation only when charset is also default.
-
9
options[:collation] ||= DEFAULT_COLLATION if options[:charset] == DEFAULT_CHARSET
-
end
-
end
-
-
1
def error_class
-
case configuration['adapter']
-
when /jdbc/
-
require 'active_record/railties/jdbcmysql_error'
-
ArJdbcMySQL::Error
-
when /mysql2/
-
Mysql2::Error
-
else
-
Mysql::Error
-
end
-
end
-
-
1
def grant_statement
-
<<-SQL
-
GRANT ALL PRIVILEGES ON #{configuration['database']}.*
-
TO '#{configuration['username']}'@'localhost'
-
IDENTIFIED BY '#{configuration['password']}' WITH GRANT OPTION;
-
SQL
-
end
-
-
1
def root_configuration_without_database
-
configuration_without_database.merge(
-
'username' => 'root',
-
'password' => root_password
-
)
-
end
-
-
1
def root_password
-
$stdout.print "Please provide the root password for your mysql installation\n>"
-
$stdin.gets.strip
-
end
-
-
1
def prepare_command_options(command)
-
2
args = [command]
-
2
args.concat(['--user', configuration['username']]) if configuration['username']
-
2
args << "--password=#{configuration['password']}" if configuration['password']
-
2
args.concat(['--default-character-set', configuration['encoding']]) if configuration['encoding']
-
2
configuration.slice('host', 'port', 'socket').each do |k, v|
-
args.concat([ "--#{k}", v ]) if v
-
end
-
2
args
-
end
-
-
end
-
end
-
end
-
1
require 'shellwords'
-
-
1
module ActiveRecord
-
1
module Tasks # :nodoc:
-
1
class PostgreSQLDatabaseTasks # :nodoc:
-
-
1
DEFAULT_ENCODING = ENV['CHARSET'] || 'utf8'
-
-
1
delegate :connection, :establish_connection, :clear_active_connections!,
-
to: ActiveRecord::Base
-
-
1
def initialize(configuration)
-
17
@configuration = configuration
-
end
-
-
1
def create(master_established = false)
-
11
establish_master_connection unless master_established
-
10
connection.create_database configuration['database'],
-
configuration.merge('encoding' => encoding)
-
10
establish_connection configuration
-
end
-
-
1
def drop
-
7
establish_master_connection
-
7
connection.drop_database configuration['database']
-
end
-
-
1
def charset
-
1
connection.encoding
-
end
-
-
1
def collation
-
1
connection.collation
-
end
-
-
1
def purge
-
5
clear_active_connections!
-
5
drop
-
5
create true
-
end
-
-
1
def structure_dump(filename)
-
1
set_psql_env
-
1
search_path = configuration['schema_search_path']
-
1
unless search_path.blank?
-
search_path = search_path.split(",").map{|search_path_part| "--schema=#{Shellwords.escape(search_path_part.strip)}" }.join(" ")
-
end
-
-
1
command = "pg_dump -i -s -x -O -f #{Shellwords.escape(filename)} #{search_path} #{Shellwords.escape(configuration['database'])}"
-
1
raise 'Error dumping database' unless Kernel.system(command)
-
-
2
File.open(filename, "a") { |f| f << "SET search_path TO #{ActiveRecord::Base.connection.schema_search_path};\n\n" }
-
end
-
-
1
def structure_load(filename)
-
1
set_psql_env
-
1
Kernel.system("psql -f #{filename} #{configuration['database']}")
-
end
-
-
1
private
-
-
1
def configuration
-
71
@configuration
-
end
-
-
1
def encoding
-
10
configuration['encoding'] || DEFAULT_ENCODING
-
end
-
-
1
def establish_master_connection
-
establish_connection configuration.merge(
-
'database' => 'postgres',
-
'schema_search_path' => 'public'
-
13
)
-
end
-
-
1
def set_psql_env
-
2
ENV['PGHOST'] = configuration['host'] if configuration['host']
-
2
ENV['PGPORT'] = configuration['port'].to_s if configuration['port']
-
2
ENV['PGPASSWORD'] = configuration['password'].to_s if configuration['password']
-
2
ENV['PGUSER'] = configuration['username'].to_s if configuration['username']
-
end
-
end
-
end
-
end
-
1
module ActiveRecord
-
1
module Tasks # :nodoc:
-
1
class SQLiteDatabaseTasks # :nodoc:
-
-
1
delegate :connection, :establish_connection, to: ActiveRecord::Base
-
-
1
def initialize(configuration, root = Rails.root)
-
13
@configuration, @root = configuration, root
-
end
-
-
1
def create
-
5
if File.exist?(configuration['database'])
-
2
$stderr.puts "#{configuration['database']} already exists"
-
2
return
-
end
-
-
3
establish_connection configuration
-
2
connection
-
end
-
-
1
def drop
-
4
require 'pathname'
-
4
path = Pathname.new configuration['database']
-
4
file = path.absolute? ? path.to_s : File.join(root, path)
-
-
4
FileUtils.rm(file) if File.exist?(file)
-
end
-
1
alias :purge :drop
-
-
1
def charset
-
1
connection.encoding
-
end
-
-
1
def structure_dump(filename)
-
1
dbfile = configuration['database']
-
1
`sqlite3 #{dbfile} .schema > #{filename}`
-
end
-
-
1
def structure_load(filename)
-
1
dbfile = configuration['database']
-
1
`sqlite3 #{dbfile} < "#{filename}"`
-
end
-
-
1
private
-
-
1
def configuration
-
16
@configuration
-
end
-
-
1
def root
-
2
@root
-
end
-
end
-
end
-
end
-
1
require 'active_support/test_case'
-
-
1
ActiveSupport::Deprecation.warn('ActiveRecord::TestCase is deprecated, please use ActiveSupport::TestCase')
-
1
module ActiveRecord
-
# = Active Record Test Case
-
#
-
# Defines some test assertions to test against SQL queries.
-
1
class TestCase < ActiveSupport::TestCase #:nodoc:
-
1
def teardown
-
3235
SQLCounter.clear_log
-
end
-
-
1
def assert_date_from_db(expected, actual, message = nil)
-
# SybaseAdapter doesn't have a separate column type just for dates,
-
# so the time is in the string and incorrectly formatted
-
1
if current_adapter?(:SybaseAdapter)
-
assert_equal expected.to_s, actual.to_date.to_s, message
-
else
-
1
assert_equal expected.to_s, actual.to_s, message
-
end
-
end
-
-
1
def assert_sql(*patterns_to_match)
-
22
SQLCounter.clear_log
-
22
yield
-
22
SQLCounter.log_all
-
ensure
-
22
failed_patterns = []
-
22
patterns_to_match.each do |pattern|
-
30
failed_patterns << pattern unless SQLCounter.log_all.any?{ |sql| pattern === sql }
-
end
-
22
assert failed_patterns.empty?, "Query pattern(s) #{failed_patterns.map{ |p| p.inspect }.join(', ')} not found.#{SQLCounter.log.size == 0 ? '' : "\nQueries:\n#{SQLCounter.log.join("\n")}"}"
-
end
-
-
1
def assert_queries(num = 1, options = {})
-
657
ignore_none = options.fetch(:ignore_none) { num == :any }
-
439
SQLCounter.clear_log
-
439
yield
-
ensure
-
439
the_log = ignore_none ? SQLCounter.log_all : SQLCounter.log
-
439
if num == :any
-
2
assert_operator the_log.size, :>=, 1, "1 or more queries expected, but none were executed."
-
else
-
437
mesg = "#{the_log.size} instead of #{num} queries were executed.#{the_log.size == 0 ? '' : "\nQueries:\n#{the_log.join("\n")}"}"
-
437
assert_equal num, the_log.size, mesg
-
end
-
end
-
-
1
def assert_no_queries(&block)
-
221
assert_queries(0, :ignore_none => true, &block)
-
end
-
-
end
-
-
1
class SQLCounter
-
1
class << self
-
1
attr_accessor :ignored_sql, :log, :log_all
-
3698
def clear_log; self.log = []; self.log_all = []; end
-
end
-
-
1
self.clear_log
-
-
1
self.ignored_sql = [/^PRAGMA (?!(table_info))/, /^SELECT currval/, /^SELECT CAST/, /^SELECT @@IDENTITY/, /^SELECT @@ROWCOUNT/, /^SAVEPOINT/, /^ROLLBACK TO SAVEPOINT/, /^RELEASE SAVEPOINT/, /^SHOW max_identifier_length/, /^BEGIN/, /^COMMIT/]
-
-
# FIXME: this needs to be refactored so specific database can add their own
-
# ignored SQL, or better yet, use a different notification for the queries
-
# instead examining the SQL content.
-
1
oracle_ignored = [/^select .*nextval/i, /^SAVEPOINT/, /^ROLLBACK TO/, /^\s*select .* from all_triggers/im]
-
1
mysql_ignored = [/^SHOW TABLES/i, /^SHOW FULL FIELDS/]
-
1
postgresql_ignored = [/^\s*select\b.*\bfrom\b.*pg_namespace\b/im, /^\s*select\b.*\battname\b.*\bfrom\b.*\bpg_attribute\b/im]
-
-
1
[oracle_ignored, mysql_ignored, postgresql_ignored].each do |db_ignored_sql|
-
3
ignored_sql.concat db_ignored_sql
-
end
-
-
1
attr_reader :ignore
-
-
1
def initialize(ignore = Regexp.union(self.class.ignored_sql))
-
1
@ignore = ignore
-
end
-
-
1
def call(name, start, finish, message_id, values)
-
67854
sql = values[:sql]
-
-
# FIXME: this seems bad. we should probably have a better way to indicate
-
# the query was cached
-
67854
return if 'CACHE' == values[:name]
-
-
67840
self.class.log_all << sql
-
67840
self.class.log << sql unless ignore =~ sql
-
end
-
end
-
-
1
ActiveSupport::Notifications.subscribe('sql.active_record', SQLCounter.new)
-
end
-
1
require 'thread'
-
-
1
module ActiveRecord
-
# See ActiveRecord::Transactions::ClassMethods for documentation.
-
1
module Transactions
-
1
extend ActiveSupport::Concern
-
-
1
class TransactionError < ActiveRecordError # :nodoc:
-
end
-
-
1
included do
-
1
define_callbacks :commit, :rollback, :terminator => "result == false", :scope => [:kind, :name]
-
end
-
-
# = Active Record Transactions
-
#
-
# Transactions are protective blocks where SQL statements are only permanent
-
# if they can all succeed as one atomic action. The classic example is a
-
# transfer between two accounts where you can only have a deposit if the
-
# withdrawal succeeded and vice versa. Transactions enforce the integrity of
-
# the database and guard the data against program errors or database
-
# break-downs. So basically you should use transaction blocks whenever you
-
# have a number of statements that must be executed together or not at all.
-
#
-
# For example:
-
#
-
# ActiveRecord::Base.transaction do
-
# david.withdrawal(100)
-
# mary.deposit(100)
-
# end
-
#
-
# This example will only take money from David and give it to Mary if neither
-
# +withdrawal+ nor +deposit+ raise an exception. Exceptions will force a
-
# ROLLBACK that returns the database to the state before the transaction
-
# began. Be aware, though, that the objects will _not_ have their instance
-
# data returned to their pre-transactional state.
-
#
-
# == Different Active Record classes in a single transaction
-
#
-
# Though the transaction class method is called on some Active Record class,
-
# the objects within the transaction block need not all be instances of
-
# that class. This is because transactions are per-database connection, not
-
# per-model.
-
#
-
# In this example a +balance+ record is transactionally saved even
-
# though +transaction+ is called on the +Account+ class:
-
#
-
# Account.transaction do
-
# balance.save!
-
# account.save!
-
# end
-
#
-
# The +transaction+ method is also available as a model instance method.
-
# For example, you can also do this:
-
#
-
# balance.transaction do
-
# balance.save!
-
# account.save!
-
# end
-
#
-
# == Transactions are not distributed across database connections
-
#
-
# A transaction acts on a single database connection. If you have
-
# multiple class-specific databases, the transaction will not protect
-
# interaction among them. One workaround is to begin a transaction
-
# on each class whose models you alter:
-
#
-
# Student.transaction do
-
# Course.transaction do
-
# course.enroll(student)
-
# student.units += course.units
-
# end
-
# end
-
#
-
# This is a poor solution, but fully distributed transactions are beyond
-
# the scope of Active Record.
-
#
-
# == +save+ and +destroy+ are automatically wrapped in a transaction
-
#
-
# Both +save+ and +destroy+ come wrapped in a transaction that ensures
-
# that whatever you do in validations or callbacks will happen under its
-
# protected cover. So you can use validations to check for values that
-
# the transaction depends on or you can raise exceptions in the callbacks
-
# to rollback, including <tt>after_*</tt> callbacks.
-
#
-
# As a consequence changes to the database are not seen outside your connection
-
# until the operation is complete. For example, if you try to update the index
-
# of a search engine in +after_save+ the indexer won't see the updated record.
-
# The +after_commit+ callback is the only one that is triggered once the update
-
# is committed. See below.
-
#
-
# == Exception handling and rolling back
-
#
-
# Also have in mind that exceptions thrown within a transaction block will
-
# be propagated (after triggering the ROLLBACK), so you should be ready to
-
# catch those in your application code.
-
#
-
# One exception is the <tt>ActiveRecord::Rollback</tt> exception, which will trigger
-
# a ROLLBACK when raised, but not be re-raised by the transaction block.
-
#
-
# *Warning*: one should not catch <tt>ActiveRecord::StatementInvalid</tt> exceptions
-
# inside a transaction block. <tt>ActiveRecord::StatementInvalid</tt> exceptions indicate that an
-
# error occurred at the database level, for example when a unique constraint
-
# is violated. On some database systems, such as PostgreSQL, database errors
-
# inside a transaction cause the entire transaction to become unusable
-
# until it's restarted from the beginning. Here is an example which
-
# demonstrates the problem:
-
#
-
# # Suppose that we have a Number model with a unique column called 'i'.
-
# Number.transaction do
-
# Number.create(:i => 0)
-
# begin
-
# # This will raise a unique constraint error...
-
# Number.create(:i => 0)
-
# rescue ActiveRecord::StatementInvalid
-
# # ...which we ignore.
-
# end
-
#
-
# # On PostgreSQL, the transaction is now unusable. The following
-
# # statement will cause a PostgreSQL error, even though the unique
-
# # constraint is no longer violated:
-
# Number.create(:i => 1)
-
# # => "PGError: ERROR: current transaction is aborted, commands
-
# # ignored until end of transaction block"
-
# end
-
#
-
# One should restart the entire transaction if an
-
# <tt>ActiveRecord::StatementInvalid</tt> occurred.
-
#
-
# == Nested transactions
-
#
-
# +transaction+ calls can be nested. By default, this makes all database
-
# statements in the nested transaction block become part of the parent
-
# transaction. For example, the following behavior may be surprising:
-
#
-
# User.transaction do
-
# User.create(:username => 'Kotori')
-
# User.transaction do
-
# User.create(:username => 'Nemu')
-
# raise ActiveRecord::Rollback
-
# end
-
# end
-
#
-
# creates both "Kotori" and "Nemu". Reason is the <tt>ActiveRecord::Rollback</tt>
-
# exception in the nested block does not issue a ROLLBACK. Since these exceptions
-
# are captured in transaction blocks, the parent block does not see it and the
-
# real transaction is committed.
-
#
-
# In order to get a ROLLBACK for the nested transaction you may ask for a real
-
# sub-transaction by passing <tt>:requires_new => true</tt>. If anything goes wrong,
-
# the database rolls back to the beginning of the sub-transaction without rolling
-
# back the parent transaction. If we add it to the previous example:
-
#
-
# User.transaction do
-
# User.create(:username => 'Kotori')
-
# User.transaction(:requires_new => true) do
-
# User.create(:username => 'Nemu')
-
# raise ActiveRecord::Rollback
-
# end
-
# end
-
#
-
# only "Kotori" is created. (This works on MySQL and PostgreSQL, but not on SQLite3.)
-
#
-
# Most databases don't support true nested transactions. At the time of
-
# writing, the only database that we're aware of that supports true nested
-
# transactions, is MS-SQL. Because of this, Active Record emulates nested
-
# transactions by using savepoints on MySQL and PostgreSQL. See
-
# http://dev.mysql.com/doc/refman/5.6/en/savepoint.html
-
# for more information about savepoints.
-
#
-
# === Callbacks
-
#
-
# There are two types of callbacks associated with committing and rolling back transactions:
-
# +after_commit+ and +after_rollback+.
-
#
-
# +after_commit+ callbacks are called on every record saved or destroyed within a
-
# transaction immediately after the transaction is committed. +after_rollback+ callbacks
-
# are called on every record saved or destroyed within a transaction immediately after the
-
# transaction or savepoint is rolled back.
-
#
-
# These callbacks are useful for interacting with other systems since you will be guaranteed
-
# that the callback is only executed when the database is in a permanent state. For example,
-
# +after_commit+ is a good spot to put in a hook to clearing a cache since clearing it from
-
# within a transaction could trigger the cache to be regenerated before the database is updated.
-
#
-
# === Caveats
-
#
-
# If you're on MySQL, then do not use DDL operations in nested transactions
-
# blocks that are emulated with savepoints. That is, do not execute statements
-
# like 'CREATE TABLE' inside such blocks. This is because MySQL automatically
-
# releases all savepoints upon executing a DDL operation. When +transaction+
-
# is finished and tries to release the savepoint it created earlier, a
-
# database error will occur because the savepoint has already been
-
# automatically released. The following example demonstrates the problem:
-
#
-
# Model.connection.transaction do # BEGIN
-
# Model.connection.transaction(:requires_new => true) do # CREATE SAVEPOINT active_record_1
-
# Model.connection.create_table(...) # active_record_1 now automatically released
-
# end # RELEASE savepoint active_record_1
-
# # ^^^^ BOOM! database error!
-
# end
-
#
-
# Note that "TRUNCATE" is also a MySQL DDL statement!
-
1
module ClassMethods
-
# See ActiveRecord::Transactions::ClassMethods for detailed documentation.
-
1
def transaction(options = {}, &block)
-
# See the ConnectionAdapters::DatabaseStatements#transaction API docs.
-
4273
connection.transaction(options, &block)
-
end
-
-
# This callback is called after a record has been created, updated, or destroyed.
-
#
-
# You can specify that the callback should only be fired by a certain action with
-
# the +:on+ option:
-
#
-
# after_commit :do_foo, :on => :create
-
# after_commit :do_bar, :on => :update
-
# after_commit :do_baz, :on => :destroy
-
#
-
# Also, to have the callback fired on create and update, but not on destroy:
-
#
-
# after_commit :do_zoo, :if => :persisted?
-
#
-
# Note that transactional fixtures do not play well with this feature. Please
-
# use the +test_after_commit+ gem to have these hooks fired in tests.
-
1
def after_commit(*args, &block)
-
12
options = args.last
-
12
if options.is_a?(Hash) && options[:on]
-
5
options[:if] = Array(options[:if])
-
5
options[:if] << "transaction_include_action?(:#{options[:on]})"
-
end
-
12
set_callback(:commit, :after, *args, &block)
-
end
-
-
# This callback is called after a create, update, or destroy are rolled back.
-
#
-
# Please check the documentation of +after_commit+ for options.
-
1
def after_rollback(*args, &block)
-
10
options = args.last
-
10
if options.is_a?(Hash) && options[:on]
-
3
options[:if] = Array(options[:if])
-
3
options[:if] << "transaction_include_action?(:#{options[:on]})"
-
end
-
10
set_callback(:rollback, :after, *args, &block)
-
end
-
end
-
-
# See ActiveRecord::Transactions::ClassMethods for detailed documentation.
-
1
def transaction(options = {}, &block)
-
8
self.class.transaction(options, &block)
-
end
-
-
1
def destroy #:nodoc:
-
496
with_transaction_returning_status { super }
-
end
-
-
1
def save(*) #:nodoc:
-
1708
rollback_active_record_state! do
-
3416
with_transaction_returning_status { super }
-
end
-
end
-
-
1
def save!(*) #:nodoc:
-
2766
with_transaction_returning_status { super }
-
end
-
-
# Reset id and @new_record if the transaction rolls back.
-
1
def rollback_active_record_state!
-
1708
remember_transaction_record_state
-
1708
yield
-
rescue Exception
-
21
restore_transaction_record_state
-
21
raise
-
ensure
-
1708
clear_transaction_record_state
-
end
-
-
# Call the after_commit callbacks
-
1
def committed! #:nodoc:
-
145
run_callbacks :commit
-
ensure
-
145
clear_transaction_record_state
-
end
-
-
# Call the after rollback callbacks. The restore_state argument indicates if the record
-
# state should be rolled back to the beginning or just to the last savepoint.
-
1
def rolledback!(force_restore_state = false) #:nodoc:
-
2732
run_callbacks :rollback
-
ensure
-
2732
restore_transaction_record_state(force_restore_state)
-
end
-
-
# Add the record to the current transaction so that the :after_rollback and :after_commit callbacks
-
# can be called.
-
1
def add_to_transaction
-
3430
if self.class.connection.add_transaction_record(self)
-
3430
remember_transaction_record_state
-
end
-
end
-
-
# Executes +method+ within a transaction and captures its return value as a
-
# status flag. If the status is true the transaction is committed, otherwise
-
# a ROLLBACK is issued. In any case the status flag is returned.
-
#
-
# This method is available within the context of an ActiveRecord::Base
-
# instance.
-
1
def with_transaction_returning_status
-
3430
status = nil
-
3430
self.class.transaction do
-
3430
add_to_transaction
-
3430
begin
-
3430
status = yield
-
rescue ActiveRecord::Rollback
-
8
@_start_transaction_state[:level] = (@_start_transaction_state[:level] || 0) - 1
-
8
status = nil
-
end
-
-
3335
raise ActiveRecord::Rollback unless status
-
end
-
3334
status
-
end
-
-
1
protected
-
-
# Save the new record state and id of a record so it can be restored later if a transaction fails.
-
1
def remember_transaction_record_state #:nodoc:
-
5138
@_start_transaction_state[:id] = id if has_attribute?(self.class.primary_key)
-
5138
@_start_transaction_state[:new_record] = @new_record
-
5138
@_start_transaction_state[:destroyed] = @destroyed
-
5138
@_start_transaction_state[:level] = (@_start_transaction_state[:level] || 0) + 1
-
5138
@_start_transaction_state[:frozen?] = @attributes.frozen?
-
end
-
-
# Clear the new record state and id of a record.
-
1
def clear_transaction_record_state #:nodoc:
-
1853
@_start_transaction_state[:level] = (@_start_transaction_state[:level] || 0) - 1
-
1853
@_start_transaction_state.clear if @_start_transaction_state[:level] < 1
-
end
-
-
# Restore the new record state and id of a record that was previously saved by a call to save_record_state.
-
1
def restore_transaction_record_state(force = false) #:nodoc:
-
2753
unless @_start_transaction_state.empty?
-
2731
@_start_transaction_state[:level] = (@_start_transaction_state[:level] || 0) - 1
-
2731
if @_start_transaction_state[:level] < 1 || force
-
2615
restore_state = @_start_transaction_state
-
2615
was_frozen = restore_state[:frozen?]
-
2615
@attributes = @attributes.dup if @attributes.frozen?
-
2615
@new_record = restore_state[:new_record]
-
2615
@destroyed = restore_state[:destroyed]
-
2615
if restore_state.has_key?(:id)
-
2610
self.id = restore_state[:id]
-
else
-
5
@attributes.delete(self.class.primary_key)
-
5
@attributes_cache.delete(self.class.primary_key)
-
end
-
2615
@attributes.freeze if was_frozen
-
2615
@_start_transaction_state.clear
-
end
-
end
-
end
-
-
# Determine if a record was created or destroyed in a transaction. State should be one of :new_record or :destroyed.
-
1
def transaction_record_state(state) #:nodoc:
-
40
@_start_transaction_state[state]
-
end
-
-
# Determine if a transaction included an action for :create, :update, or :destroy. Used in filtering callbacks.
-
1
def transaction_include_action?(action) #:nodoc:
-
58
case action
-
when :create
-
20
transaction_record_state(:new_record)
-
when :destroy
-
18
destroyed?
-
when :update
-
20
!(transaction_record_state(:new_record) || destroyed?)
-
end
-
end
-
end
-
end
-
1
module ActiveRecord
-
1
module Translation
-
1
include ActiveModel::Translation
-
-
# Set the lookup ancestors for ActiveModel.
-
1
def lookup_ancestors #:nodoc:
-
790
klass = self
-
790
classes = [klass]
-
790
return classes if klass == ActiveRecord::Base
-
-
789
while klass != klass.base_class
-
270
classes << klass = klass.superclass
-
end
-
789
classes
-
end
-
-
# Set the i18n scope to overwrite ActiveModel.
-
1
def i18n_scope #:nodoc:
-
1479
:activerecord
-
end
-
end
-
end
-
1
module ActiveRecord
-
# = Active Record RecordInvalid
-
#
-
# Raised by <tt>save!</tt> and <tt>create!</tt> when the record is invalid. Use the
-
# +record+ method to retrieve the record which did not validate.
-
#
-
# begin
-
# complex_operation_that_calls_save!_internally
-
# rescue ActiveRecord::RecordInvalid => invalid
-
# puts invalid.record.errors
-
# end
-
1
class RecordInvalid < ActiveRecordError
-
1
attr_reader :record # :nodoc:
-
1
def initialize(record) # :nodoc:
-
41
@record = record
-
41
errors = @record.errors.full_messages.join(", ")
-
41
super(I18n.t(:"#{@record.class.i18n_scope}.errors.messages.record_invalid", :errors => errors, :default => :"errors.messages.record_invalid"))
-
end
-
end
-
-
# = Active Record Validations
-
#
-
# Active Record includes the majority of its validations from <tt>ActiveModel::Validations</tt>
-
# all of which accept the <tt>:on</tt> argument to define the context where the
-
# validations are active. Active Record will always supply either the context of
-
# <tt>:create</tt> or <tt>:update</tt> dependent on whether the model is a
-
# <tt>new_record?</tt>.
-
1
module Validations
-
1
extend ActiveSupport::Concern
-
1
include ActiveModel::Validations
-
-
1
module ClassMethods
-
# Creates an object just like Base.create but calls <tt>save!</tt> instead of +save+
-
# so an exception is raised if the record is invalid.
-
1
def create!(attributes = nil, &block)
-
821
if attributes.is_a?(Array)
-
10
attributes.collect { |attr| create!(attr, &block) }
-
else
-
817
object = new(attributes)
-
817
yield(object) if block_given?
-
817
object.save!
-
802
object
-
end
-
end
-
end
-
-
# The validation process on save can be skipped by passing <tt>validate: false</tt>.
-
# The regular Base#save method is replaced with this when the validations
-
# module is mixed in, which it is by default.
-
1
def save(options={})
-
1708
perform_validations(options) ? super : false
-
end
-
-
# Attempts to save the record just like Base#save but will raise a +RecordInvalid+
-
# exception instead of returning +false+ if the record is not valid.
-
1
def save!(options={})
-
1383
perform_validations(options) ? super : raise(RecordInvalid.new(self))
-
end
-
-
# Runs all the validations within the specified context. Returns +true+ if
-
# no errors are found, +false+ otherwise.
-
#
-
# If the argument is +false+ (default is +nil+), the context is set to <tt>:create</tt> if
-
# <tt>new_record?</tt> is +true+, and to <tt>:update</tt> if it is not.
-
#
-
# Validations with no <tt>:on</tt> option will run no matter the context. Validations with
-
# some <tt>:on</tt> option will only run in the specified context.
-
1
def valid?(context = nil)
-
3407
context ||= (new_record? ? :create : :update)
-
3407
output = super(context)
-
3407
errors.empty? && output
-
end
-
-
1
protected
-
-
1
def perform_validations(options={}) # :nodoc:
-
3091
perform_validation = options[:validate] != false
-
3091
perform_validation ? valid?(options[:context]) : true
-
end
-
end
-
end
-
-
1
require "active_record/validations/associated"
-
1
require "active_record/validations/uniqueness"
-
1
require "active_record/validations/presence"
-
1
module ActiveRecord
-
1
module Validations
-
1
class AssociatedValidator < ActiveModel::EachValidator #:nodoc:
-
1
def validate_each(record, attribute, value)
-
87
if Array.wrap(value).reject {|r| r.marked_for_destruction? || r.valid?(record.validation_context) }.any?
-
13
record.errors.add(attribute, :invalid, options.merge(:value => value))
-
end
-
end
-
end
-
-
1
module ClassMethods
-
# Validates whether the associated object or objects are all valid
-
# themselves. Works with any kind of association.
-
#
-
# class Book < ActiveRecord::Base
-
# has_many :pages
-
# belongs_to :library
-
#
-
# validates_associated :pages, :library
-
# end
-
#
-
# WARNING: This validation must not be used on both ends of an association.
-
# Doing so will lead to a circular dependency and cause infinite recursion.
-
#
-
# NOTE: This validation will not fail if the association hasn't been
-
# assigned. If you want to ensure that the association is both present and
-
# guaranteed to be valid, you also need to use +validates_presence_of+.
-
#
-
# Configuration options:
-
#
-
# * <tt>:message</tt> - A custom error message (default is: "is invalid").
-
# * <tt>:on</tt> - Specifies when this validation is active. Runs in all
-
# validation contexts by default (+nil+), other options are <tt>:create</tt>
-
# and <tt>:update</tt>.
-
# * <tt>:if</tt> - Specifies a method, proc or string to call to determine
-
# if the validation should occur (e.g. <tt>if: :allow_validation</tt>,
-
# or <tt>if: Proc.new { |user| user.signup_step > 2 }</tt>). The method,
-
# proc or string should return or evaluate to a +true+ or +false+ value.
-
# * <tt>:unless</tt> - Specifies a method, proc or string to call to
-
# determine if the validation should not occur (e.g. <tt>unless: :skip_validation</tt>,
-
# or <tt>unless: Proc.new { |user| user.signup_step <= 2 }</tt>). The
-
# method, proc or string should return or evaluate to a +true+ or +false+
-
# value.
-
1
def validates_associated(*attr_names)
-
11
validates_with AssociatedValidator, _merge_attributes(attr_names)
-
end
-
end
-
end
-
end
-
1
module ActiveRecord
-
1
module Validations
-
1
class PresenceValidator < ActiveModel::Validations::PresenceValidator # :nodoc:
-
1
def validate(record)
-
1388
super
-
1388
attributes.each do |attribute|
-
1388
next unless record.class.reflect_on_association(attribute)
-
19
associated_records = Array(record.send(attribute))
-
-
# Superclass validates presence. Ensure present records aren't about to be destroyed.
-
33
if associated_records.present? && associated_records.all? { |r| r.marked_for_destruction? }
-
2
record.errors.add(attribute, :blank, options)
-
end
-
end
-
end
-
end
-
-
1
module ClassMethods
-
# Validates that the specified attributes are not blank (as defined by
-
# Object#blank?), and, if the attribute is an association, that the
-
# associated object is not marked for destruction. Happens by default
-
# on save.
-
#
-
# class Person < ActiveRecord::Base
-
# has_one :face
-
# validates_presence_of :face
-
# end
-
#
-
# The face attribute must be in the object and it cannot be blank or marked
-
# for destruction.
-
#
-
# If you want to validate the presence of a boolean field (where the real values
-
# are true and false), you will want to use
-
# <tt>validates_inclusion_of :field_name, in: [true, false]</tt>.
-
#
-
# This is due to the way Object#blank? handles boolean values:
-
# <tt>false.blank? # => true</tt>.
-
#
-
# This validator defers to the ActiveModel validation for presence, adding the
-
# check to see that an associated object is not marked for destruction. This
-
# prevents the parent object from validating successfully and saving, which then
-
# deletes the associated object, thus putting the parent object into an invalid
-
# state.
-
#
-
# Configuration options:
-
# * <tt>:message</tt> - A custom error message (default is: "can't be blank").
-
# * <tt>:on</tt> - Specifies when this validation is active. Runs in all
-
# validation contexts by default (+nil+), other options are <tt>:create</tt>
-
# and <tt>:update</tt>.
-
# * <tt>:if</tt> - Specifies a method, proc or string to call to determine if
-
# the validation should occur (e.g. <tt>if: :allow_validation</tt>, or
-
# <tt>if: Proc.new { |user| user.signup_step > 2 }</tt>). The method, proc
-
# or string should return or evaluate to a +true+ or +false+ value.
-
# * <tt>:unless</tt> - Specifies a method, proc or string to call to determine
-
# if the validation should not occur (e.g. <tt>unless: :skip_validation</tt>,
-
# or <tt>unless: Proc.new { |user| user.signup_step <= 2 }</tt>). The method,
-
# proc or string should return or evaluate to a +true+ or +false+ value.
-
# * <tt>:strict</tt> - Specifies whether validation should be strict.
-
# See <tt>ActiveModel::Validation#validates!</tt> for more information.
-
1
def validates_presence_of(*attr_names)
-
39
validates_with PresenceValidator, _merge_attributes(attr_names)
-
end
-
end
-
end
-
end
-
1
require 'active_support/core_ext/array/prepend_and_append'
-
-
1
module ActiveRecord
-
1
module Validations
-
1
class UniquenessValidator < ActiveModel::EachValidator # :nodoc:
-
1
def initialize(options)
-
27
super(options.reverse_merge(:case_sensitive => true))
-
end
-
-
# Unfortunately, we have to tie Uniqueness validators to a class.
-
1
def setup(klass)
-
27
@klass = klass
-
end
-
-
1
def validate_each(record, attribute, value)
-
117
finder_class = find_finder_class_for(record)
-
117
table = finder_class.arel_table
-
-
117
coder = record.class.serialized_attributes[attribute.to_s]
-
-
117
if value && coder
-
19
value = coder.dump value
-
end
-
-
117
relation = build_relation(finder_class, table, attribute, value)
-
117
relation = relation.and(table[finder_class.primary_key.to_sym].not_eq(record.send(:id))) if record.persisted?
-
-
117
Array(options[:scope]).each do |scope_item|
-
37
reflection = record.class.reflect_on_association(scope_item)
-
37
if reflection
-
4
scope_value = record.send(reflection.foreign_key)
-
4
scope_item = reflection.foreign_key
-
else
-
33
scope_value = record.read_attribute(scope_item)
-
end
-
37
relation = relation.and(table[scope_item].eq(scope_value))
-
end
-
-
117
relation = finder_class.unscoped.where(relation)
-
-
117
if options[:conditions]
-
4
relation = relation.merge(options[:conditions])
-
end
-
-
117
if relation.exists?
-
46
record.errors.add(attribute, :taken, options.except(:case_sensitive, :scope, :conditions).merge(:value => value))
-
end
-
end
-
-
1
protected
-
-
# The check for an existing value should be run from a class that
-
# isn't abstract. This means working down from the current class
-
# (self), to the first non-abstract class. Since classes don't know
-
# their subclasses, we have to build the hierarchy between self and
-
# the record's class.
-
1
def find_finder_class_for(record) #:nodoc:
-
117
class_hierarchy = [record.class]
-
-
117
while class_hierarchy.first != @klass
-
20
class_hierarchy.prepend(class_hierarchy.first.superclass)
-
end
-
-
242
class_hierarchy.detect { |klass| !klass.abstract_class? }
-
end
-
-
1
def build_relation(klass, table, attribute, value) #:nodoc:
-
117
if reflection = klass.reflect_on_association(attribute)
-
4
attribute = reflection.foreign_key
-
4
value = value.attributes[reflection.primary_key_column.name]
-
end
-
-
117
column = klass.columns_hash[attribute.to_s]
-
117
value = column.limit ? value.to_s[0, column.limit] : value.to_s if !value.nil? && column.text?
-
-
117
if !options[:case_sensitive] && value && column.text?
-
# will use SQL LOWER function before comparison, unless it detects a case insensitive collation
-
14
relation = klass.connection.case_insensitive_comparison(table, attribute, column, value)
-
else
-
103
value = klass.connection.case_sensitive_modifier(value) unless value.nil?
-
103
relation = table[attribute].eq(value)
-
end
-
-
117
relation
-
end
-
end
-
-
1
module ClassMethods
-
# Validates whether the value of the specified attributes are unique
-
# across the system. Useful for making sure that only one user
-
# can be named "davidhh".
-
#
-
# class Person < ActiveRecord::Base
-
# validates_uniqueness_of :user_name
-
# end
-
#
-
# It can also validate whether the value of the specified attributes are
-
# unique based on a <tt>:scope</tt> parameter:
-
#
-
# class Person < ActiveRecord::Base
-
# validates_uniqueness_of :user_name, scope: :account_id
-
# end
-
#
-
# Or even multiple scope parameters. For example, making sure that a
-
# teacher can only be on the schedule once per semester for a particular
-
# class.
-
#
-
# class TeacherSchedule < ActiveRecord::Base
-
# validates_uniqueness_of :teacher_id, scope: [:semester_id, :class_id]
-
# end
-
#
-
# It is also possible to limit the uniqueness constraint to a set of
-
# records matching certain conditions. In this example archived articles
-
# are not being taken into consideration when validating uniqueness
-
# of the title attribute:
-
#
-
# class Article < ActiveRecord::Base
-
# validates_uniqueness_of :title, conditions: where('status != ?', 'archived')
-
# end
-
#
-
# When the record is created, a check is performed to make sure that no
-
# record exists in the database with the given value for the specified
-
# attribute (that maps to a column). When the record is updated,
-
# the same check is made but disregarding the record itself.
-
#
-
# Configuration options:
-
#
-
# * <tt>:message</tt> - Specifies a custom error message (default is:
-
# "has already been taken").
-
# * <tt>:scope</tt> - One or more columns by which to limit the scope of
-
# the uniqueness constraint.
-
# * <tt>:conditions</tt> - Specify the conditions to be included as a
-
# <tt>WHERE</tt> SQL fragment to limit the uniqueness constraint lookup
-
# (e.g. <tt>conditions: where('status = ?', 'active')</tt>).
-
# * <tt>:case_sensitive</tt> - Looks for an exact match. Ignored by
-
# non-text columns (+true+ by default).
-
# * <tt>:allow_nil</tt> - If set to +true+, skips this validation if the
-
# attribute is +nil+ (default is +false+).
-
# * <tt>:allow_blank</tt> - If set to +true+, skips this validation if the
-
# attribute is blank (default is +false+).
-
# * <tt>:if</tt> - Specifies a method, proc or string to call to determine
-
# if the validation should occur (e.g. <tt>if: :allow_validation</tt>,
-
# or <tt>if: Proc.new { |user| user.signup_step > 2 }</tt>). The method,
-
# proc or string should return or evaluate to a +true+ or +false+ value.
-
# * <tt>:unless</tt> - Specifies a method, proc or string to call to
-
# determine if the validation should ot occur (e.g. <tt>unless: :skip_validation</tt>,
-
# or <tt>unless: Proc.new { |user| user.signup_step <= 2 }</tt>). The
-
# method, proc or string should return or evaluate to a +true+ or +false+
-
# value.
-
#
-
# === Concurrency and integrity
-
#
-
# Using this validation method in conjunction with ActiveRecord::Base#save
-
# does not guarantee the absence of duplicate record insertions, because
-
# uniqueness checks on the application level are inherently prone to race
-
# conditions. For example, suppose that two users try to post a Comment at
-
# the same time, and a Comment's title must be unique. At the database-level,
-
# the actions performed by these users could be interleaved in the following manner:
-
#
-
# User 1 | User 2
-
# ------------------------------------+--------------------------------------
-
# # User 1 checks whether there's |
-
# # already a comment with the title |
-
# # 'My Post'. This is not the case. |
-
# SELECT * FROM comments |
-
# WHERE title = 'My Post' |
-
# |
-
# | # User 2 does the same thing and also
-
# | # infers that his title is unique.
-
# | SELECT * FROM comments
-
# | WHERE title = 'My Post'
-
# |
-
# # User 1 inserts his comment. |
-
# INSERT INTO comments |
-
# (title, content) VALUES |
-
# ('My Post', 'hi!') |
-
# |
-
# | # User 2 does the same thing.
-
# | INSERT INTO comments
-
# | (title, content) VALUES
-
# | ('My Post', 'hello!')
-
# |
-
# | # ^^^^^^
-
# | # Boom! We now have a duplicate
-
# | # title!
-
#
-
# This could even happen if you use transactions with the 'serializable'
-
# isolation level. The best way to work around this problem is to add a unique
-
# index to the database table using
-
# ActiveRecord::ConnectionAdapters::SchemaStatements#add_index. In the
-
# rare case that a race condition occurs, the database will guarantee
-
# the field's uniqueness.
-
#
-
# When the database catches such a duplicate insertion,
-
# ActiveRecord::Base#save will raise an ActiveRecord::StatementInvalid
-
# exception. You can either choose to let this error propagate (which
-
# will result in the default Rails exception page being shown), or you
-
# can catch it and restart the transaction (e.g. by telling the user
-
# that the title already exists, and asking him to re-enter the title).
-
# This technique is also known as optimistic concurrency control:
-
# http://en.wikipedia.org/wiki/Optimistic_concurrency_control.
-
#
-
# The bundled ActiveRecord::ConnectionAdapters distinguish unique index
-
# constraint errors from other types of database errors by throwing an
-
# ActiveRecord::RecordNotUnique exception. For other adapters you will
-
# have to parse the (database-specific) exception message to detect such
-
# a case.
-
#
-
# The following bundled adapters throw the ActiveRecord::RecordNotUnique exception:
-
#
-
# * ActiveRecord::ConnectionAdapters::MysqlAdapter.
-
# * ActiveRecord::ConnectionAdapters::Mysql2Adapter.
-
# * ActiveRecord::ConnectionAdapters::SQLite3Adapter.
-
# * ActiveRecord::ConnectionAdapters::PostgreSQLAdapter.
-
1
def validates_uniqueness_of(*attr_names)
-
26
validates_with UniquenessValidator, _merge_attributes(attr_names)
-
end
-
end
-
end
-
end
-
1
module ActiveRecord
-
1
module VERSION #:nodoc:
-
1
MAJOR = 4
-
1
MINOR = 0
-
1
TINY = 0
-
1
PRE = "beta"
-
-
1
STRING = [MAJOR, MINOR, TINY, PRE].compact.join('.')
-
end
-
end
-
#--
-
# Copyright (c) 2005-2012 David Heinemeier Hansson
-
#
-
# Permission is hereby granted, free of charge, to any person obtaining
-
# a copy of this software and associated documentation files (the
-
# "Software"), to deal in the Software without restriction, including
-
# without limitation the rights to use, copy, modify, merge, publish,
-
# distribute, sublicense, and/or sell copies of the Software, and to
-
# permit persons to whom the Software is furnished to do so, subject to
-
# the following conditions:
-
#
-
# The above copyright notice and this permission notice shall be
-
# included in all copies or substantial portions of the Software.
-
#
-
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
-
# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
-
# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
-
# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
-
# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
-
# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
-
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
-
#++
-
-
1
require 'securerandom'
-
1
require "active_support/dependencies/autoload"
-
1
require "active_support/version"
-
1
require "active_support/logger"
-
1
require "active_support/lazy_load_hooks"
-
-
1
module ActiveSupport
-
1
extend ActiveSupport::Autoload
-
-
1
autoload :Concern
-
1
autoload :Dependencies
-
1
autoload :DescendantsTracker
-
1
autoload :FileUpdateChecker
-
1
autoload :LogSubscriber
-
1
autoload :Notifications
-
-
1
eager_autoload do
-
1
autoload :BacktraceCleaner
-
1
autoload :BasicObject
-
1
autoload :Benchmarkable
-
1
autoload :Cache
-
1
autoload :Callbacks
-
1
autoload :Configurable
-
1
autoload :Deprecation
-
1
autoload :Gzip
-
1
autoload :Inflector
-
1
autoload :JSON
-
1
autoload :KeyGenerator
-
1
autoload :MessageEncryptor
-
1
autoload :MessageVerifier
-
1
autoload :Multibyte
-
1
autoload :OptionMerger
-
1
autoload :OrderedHash
-
1
autoload :OrderedOptions
-
1
autoload :StringInquirer
-
1
autoload :TaggedLogging
-
1
autoload :XmlMini
-
end
-
-
1
autoload :Rescuable
-
1
autoload :SafeBuffer, "active_support/core_ext/string/output_safety"
-
1
autoload :TestCase
-
end
-
-
1
autoload :I18n, "active_support/i18n"
-
1
module ActiveSupport
-
# A class with no predefined methods that behaves similarly to Builder's
-
# BlankSlate. Used for proxy classes.
-
1
class BasicObject < ::BasicObject
-
1
undef_method :==
-
1
undef_method :equal?
-
-
# Let ActiveSupport::BasicObject at least raise exceptions.
-
1
def raise(*args)
-
::Object.send(:raise, *args)
-
end
-
end
-
end
-
1
require 'active_support/core_ext/benchmark'
-
1
require 'active_support/core_ext/hash/keys'
-
-
1
module ActiveSupport
-
1
module Benchmarkable
-
# Allows you to measure the execution time of a block in a template and
-
# records the result to the log. Wrap this block around expensive operations
-
# or possible bottlenecks to get a time reading for the operation. For
-
# example, let's say you thought your file processing method was taking too
-
# long; you could wrap it in a benchmark block.
-
#
-
# <% benchmark 'Process data files' do %>
-
# <%= expensive_files_operation %>
-
# <% end %>
-
#
-
# That would add something like "Process data files (345.2ms)" to the log,
-
# which you can then use to compare timings when optimizing your code.
-
#
-
# You may give an optional logger level (<tt>:debug</tt>, <tt>:info</tt>,
-
# <tt>:warn</tt>, <tt>:error</tt>) as the <tt>:level</tt> option. The
-
# default logger level value is <tt>:info</tt>.
-
#
-
# <% benchmark 'Low-level files', level: :debug do %>
-
# <%= lowlevel_files_operation %>
-
# <% end %>
-
#
-
# Finally, you can pass true as the third argument to silence all log
-
# activity (other than the timing information) from inside the block. This
-
# is great for boiling down a noisy block to just a single statement that
-
# produces one log line:
-
#
-
# <% benchmark 'Process data files', level: :info, silence: true do %>
-
# <%= expensive_and_chatty_files_operation %>
-
# <% end %>
-
1
def benchmark(message = "Benchmarking", options = {})
-
4
if logger
-
4
options.assert_valid_keys(:level, :silence)
-
4
options[:level] ||= :info
-
-
4
result = nil
-
8
ms = Benchmark.ms { result = options[:silence] ? silence { yield } : yield }
-
4
logger.send(options[:level], '%s (%.1fms)' % [ message, ms ])
-
4
result
-
else
-
yield
-
end
-
end
-
-
# Silence the logger during the execution of the block.
-
1
def silence
-
2
message = "ActiveSupport::Benchmarkable#silence is deprecated. It will be removed from Rails 4.1."
-
2
ActiveSupport::Deprecation.warn message
-
2
old_logger_level, logger.level = logger.level, ::Logger::ERROR if logger
-
2
yield
-
ensure
-
2
logger.level = old_logger_level if logger
-
end
-
end
-
end
-
1
require 'active_support/deprecation'
-
1
require 'active_support/logger'
-
-
1
module ActiveSupport
-
1
BufferedLogger = ActiveSupport::Deprecation::DeprecatedConstantProxy.new(
-
'BufferedLogger', '::ActiveSupport::Logger')
-
end
-
1
begin
-
1
require 'builder'
-
rescue LoadError => e
-
$stderr.puts "You don't have builder installed in your application. Please add it to your Gemfile and run bundle install"
-
raise e
-
end
-
1
require 'active_support/concern'
-
1
require 'active_support/descendants_tracker'
-
1
require 'active_support/core_ext/class/attribute'
-
1
require 'active_support/core_ext/kernel/reporting'
-
1
require 'active_support/core_ext/kernel/singleton_class'
-
-
1
module ActiveSupport
-
# Callbacks are code hooks that are run at key points in an object's lifecycle.
-
# The typical use case is to have a base class define a set of callbacks
-
# relevant to the other functionality it supplies, so that subclasses can
-
# install callbacks that enhance or modify the base functionality without
-
# needing to override or redefine methods of the base class.
-
#
-
# Mixing in this module allows you to define the events in the object's
-
# lifecycle that will support callbacks (via +ClassMethods.define_callbacks+),
-
# set the instance methods, procs, or callback objects to be called (via
-
# +ClassMethods.set_callback+), and run the installed callbacks at the
-
# appropriate times (via +run_callbacks+).
-
#
-
# Three kinds of callbacks are supported: before callbacks, run before a
-
# certain event; after callbacks, run after the event; and around callbacks,
-
# blocks that surround the event, triggering it when they yield. Callback code
-
# can be contained in instance methods, procs or lambdas, or callback objects
-
# that respond to certain predetermined methods. See +ClassMethods.set_callback+
-
# for details.
-
#
-
# class Record
-
# include ActiveSupport::Callbacks
-
# define_callbacks :save
-
#
-
# def save
-
# run_callbacks :save do
-
# puts "- save"
-
# end
-
# end
-
# end
-
#
-
# class PersonRecord < Record
-
# set_callback :save, :before, :saving_message
-
# def saving_message
-
# puts "saving..."
-
# end
-
#
-
# set_callback :save, :after do |object|
-
# puts "saved"
-
# end
-
# end
-
#
-
# person = PersonRecord.new
-
# person.save
-
#
-
# Output:
-
# saving...
-
# - save
-
# saved
-
1
module Callbacks
-
1
extend Concern
-
-
1
included do
-
3
extend ActiveSupport::DescendantsTracker
-
end
-
-
# Runs the callbacks for the given event.
-
#
-
# Calls the before and around callbacks in the order they were set, yields
-
# the block (if given one), and then runs the after callbacks in reverse
-
# order.
-
#
-
# If the callback chain was halted, returns +false+. Otherwise returns the
-
# result of the block, or +true+ if no block is given.
-
#
-
# run_callbacks :save do
-
# save
-
# end
-
1
def run_callbacks(kind, &block)
-
78613
runner_name = self.class.__define_callbacks(kind, self)
-
78613
send(runner_name, &block)
-
end
-
-
1
private
-
-
# A hook invoked everytime a before callback is halted.
-
# This can be overridden in AS::Callback implementors in order
-
# to provide better debugging/logging.
-
1
def halted_callback_hook(filter)
-
end
-
-
1
class Callback #:nodoc:#
-
1
@@_callback_sequence = 0
-
-
1
attr_accessor :chain, :filter, :kind, :options, :klass, :raw_filter
-
-
1
def initialize(chain, filter, kind, options, klass)
-
2233
@chain, @kind, @klass = chain, kind, klass
-
2233
deprecate_per_key_option(options)
-
2233
normalize_options!(options)
-
-
2233
@raw_filter, @options = filter, options
-
2233
@filter = _compile_filter(filter)
-
2233
recompile_options!
-
end
-
-
1
def deprecate_per_key_option(options)
-
2233
if options[:per_key]
-
raise NotImplementedError, ":per_key option is no longer supported. Use generic :if and :unless options instead."
-
end
-
end
-
-
1
def clone(chain, klass)
-
obj = super()
-
obj.chain = chain
-
obj.klass = klass
-
obj.options = @options.dup
-
obj.options[:if] = @options[:if].dup
-
obj.options[:unless] = @options[:unless].dup
-
obj
-
end
-
-
1
def normalize_options!(options)
-
2233
options[:if] = Array(options[:if])
-
2233
options[:unless] = Array(options[:unless])
-
end
-
-
1
def name
-
106
chain.name
-
end
-
-
1
def next_id
-
4454
@@_callback_sequence += 1
-
end
-
-
1
def matches?(_kind, _filter)
-
21128
@kind == _kind && @filter == _filter
-
end
-
-
1
def _update_filter(filter_options, new_options)
-
filter_options[:if].concat(Array(new_options[:unless])) if new_options.key?(:unless)
-
filter_options[:unless].concat(Array(new_options[:if])) if new_options.key?(:if)
-
end
-
-
1
def recompile!(_options)
-
deprecate_per_key_option(_options)
-
_update_filter(self.options, _options)
-
-
recompile_options!
-
end
-
-
# Wraps code with filter
-
1
def apply(code)
-
2914
case @kind
-
when :before
-
<<-RUBY_EVAL
-
1393
if !halted && #{@compiled_options}
-
# This double assignment is to prevent warnings in 1.9.3 as
-
# the `result` variable is not always used except if the
-
# terminator code refers to it.
-
result = result = #{@filter}
-
halted = (#{chain.config[:terminator]})
-
if halted
-
halted_callback_hook(#{@raw_filter.inspect.inspect})
-
end
-
end
-
#{code}
-
RUBY_EVAL
-
when :after
-
<<-RUBY_EVAL
-
1520
#{code}
-
if #{!chain.config[:skip_after_callbacks_if_terminated] || "!halted"} && #{@compiled_options}
-
#{@filter}
-
end
-
RUBY_EVAL
-
when :around
-
1
name = define_conditional_callback
-
<<-RUBY_EVAL
-
1
#{name}(halted) do
-
#{code}
-
value
-
end
-
RUBY_EVAL
-
end
-
end
-
-
1
private
-
-
# Compile around filters with conditions into proxy methods
-
# that contain the conditions.
-
#
-
# For `set_callback :save, :around, :filter_name, if: :condition':
-
#
-
# def _conditional_callback_save_17
-
# if condition
-
# filter_name do
-
# yield self
-
# end
-
# else
-
# yield self
-
# end
-
# end
-
1
def define_conditional_callback
-
1
name = "_conditional_callback_#{@kind}_#{next_id}"
-
1
@klass.class_eval <<-RUBY_EVAL, __FILE__, __LINE__ + 1
-
def #{name}(halted)
-
if #{@compiled_options} && !halted
-
#{@filter} do
-
yield self
-
end
-
else
-
yield self
-
end
-
end
-
RUBY_EVAL
-
1
name
-
end
-
-
# Options support the same options as filters themselves (and support
-
# symbols, string, procs, and objects), so compile a conditional
-
# expression based on the options.
-
1
def recompile_options!
-
2233
conditions = ["true"]
-
-
2233
unless options[:if].empty?
-
1108
conditions << Array(_compile_filter(options[:if]))
-
end
-
-
2233
unless options[:unless].empty?
-
4
conditions << Array(_compile_filter(options[:unless])).map {|f| "!#{f}"}
-
end
-
-
2233
@compiled_options = conditions.flatten.join(" && ")
-
end
-
-
# Filters support:
-
#
-
# Arrays:: Used in conditions. This is used to specify
-
# multiple conditions. Used internally to
-
# merge conditions from skip_* filters.
-
# Symbols:: A method to call.
-
# Strings:: Some content to evaluate.
-
# Procs:: A proc to call with the object.
-
# Objects:: An object with a <tt>before_foo</tt> method on it to call.
-
#
-
# All of these objects are compiled into methods and handled
-
# the same after this point:
-
#
-
# Arrays:: Merged together into a single filter.
-
# Symbols:: Already methods.
-
# Strings:: class_eval'ed into methods.
-
# Procs:: define_method'ed into methods.
-
# Objects::
-
# a method is created that calls the before_foo method
-
# on the object.
-
1
def _compile_filter(filter)
-
4453
method_name = "_callback_#{@kind}_#{next_id}"
-
4453
case filter
-
when Array
-
2220
filter.map {|f| _compile_filter(f)}
-
when Symbol
-
1923
filter
-
when String
-
1221
"(#{filter})"
-
when Proc
-
93
@klass.send(:define_method, method_name, &filter)
-
93
return method_name if filter.arity <= 0
-
-
53
method_name << (filter.arity == 1 ? "(self)" : " self, Proc.new ")
-
else
-
2052
@klass.send(:define_method, "#{method_name}_object") { filter }
-
-
106
_normalize_legacy_filter(kind, filter)
-
106
scopes = Array(chain.config[:scope])
-
227
method_to_call = scopes.map{ |s| s.is_a?(Symbol) ? send(s) : s }.join("_")
-
-
106
@klass.class_eval <<-RUBY_EVAL, __FILE__, __LINE__ + 1
-
def #{method_name}(&blk)
-
#{method_name}_object.send(:#{method_to_call}, self, &blk)
-
end
-
RUBY_EVAL
-
-
106
method_name
-
end
-
end
-
-
1
def _normalize_legacy_filter(kind, filter)
-
106
if !filter.respond_to?(kind) && filter.respond_to?(:filter)
-
message = "Filter object with #filter method is deprecated. Define method corresponding " \
-
"to filter type (#before, #after or #around)."
-
ActiveSupport::Deprecation.warn message
-
filter.singleton_class.class_eval <<-RUBY_EVAL, __FILE__, __LINE__ + 1
-
def #{kind}(context, &block) filter(context, &block) end
-
RUBY_EVAL
-
106
elsif filter.respond_to?(:before) && filter.respond_to?(:after) && kind == :around && !filter.respond_to?(:around)
-
message = "Filter object with #before and #after methods is deprecated. Define #around method instead."
-
ActiveSupport::Deprecation.warn message
-
def filter.around(context)
-
should_continue = before(context)
-
yield if should_continue
-
after(context)
-
end
-
end
-
end
-
end
-
-
# An Array with a compile method.
-
1
class CallbackChain < Array #:nodoc:#
-
1
attr_reader :name, :config
-
-
1
def initialize(name, config)
-
15
@name = name
-
15
@config = {
-
:terminator => "false",
-
:scope => [ :kind ]
-
}.merge(config)
-
end
-
-
1
def compile
-
2211
method = []
-
2211
method << "value = nil"
-
2211
method << "halted = false"
-
-
2211
callbacks = "value = !halted && (!block_given? || yield)"
-
2211
reverse_each do |callback|
-
2914
callbacks = callback.apply(callbacks)
-
end
-
2211
method << callbacks
-
-
2211
method << "value"
-
2211
method.join("\n")
-
end
-
-
end
-
-
1
module ClassMethods
-
-
# This method defines callback chain method for the given kind
-
# if it was not yet defined.
-
# This generated method plays caching role.
-
1
def __define_callbacks(kind, object) #:nodoc:
-
78613
name = __callback_runner_name(kind)
-
78613
unless object.respond_to?(name, true)
-
2211
str = object.send("_#{kind}_callbacks").compile
-
2211
class_eval <<-RUBY_EVAL, __FILE__, __LINE__ + 1
-
def #{name}() #{str} end
-
protected :#{name}
-
RUBY_EVAL
-
end
-
78613
name
-
end
-
-
1
def __reset_runner(symbol)
-
4283
name = __callback_runner_name(symbol)
-
4283
undef_method(name) if method_defined?(name)
-
end
-
-
1
def __callback_runner_name(kind)
-
82896
"_run__#{self.name.hash.abs}__#{kind}__callbacks"
-
end
-
-
# This is used internally to append, prepend and skip callbacks to the
-
# CallbackChain.
-
1
def __update_callbacks(name, filters = [], block = nil) #:nodoc:
-
2233
type = [:before, :after, :around].include?(filters.first) ? filters.shift : :before
-
2233
options = filters.last.is_a?(Hash) ? filters.pop : {}
-
2233
filters.unshift(block) if block
-
-
2233
([self] + ActiveSupport::DescendantsTracker.descendants(self)).reverse.each do |target|
-
2957
chain = target.send("_#{name}_callbacks")
-
2957
yield target, chain.dup, type, filters, options
-
2957
target.__reset_runner(name)
-
end
-
end
-
-
# Install a callback for the given event.
-
#
-
# set_callback :save, :before, :before_meth
-
# set_callback :save, :after, :after_meth, if: :condition
-
# set_callback :save, :around, ->(r, &block) { stuff; result = block.call; stuff }
-
#
-
# The second arguments indicates whether the callback is to be run +:before+,
-
# +:after+, or +:around+ the event. If omitted, +:before+ is assumed. This
-
# means the first example above can also be written as:
-
#
-
# set_callback :save, :before_meth
-
#
-
# The callback can specified as a symbol naming an instance method; as a
-
# proc, lambda, or block; as a string to be instance evaluated; or as an
-
# object that responds to a certain method determined by the <tt>:scope</tt>
-
# argument to +define_callback+.
-
#
-
# If a proc, lambda, or block is given, its body is evaluated in the context
-
# of the current object. It can also optionally accept the current object as
-
# an argument.
-
#
-
# Before and around callbacks are called in the order that they are set;
-
# after callbacks are called in the reverse order.
-
#
-
# Around callbacks can access the return value from the event, if it
-
# wasn't halted, from the +yield+ call.
-
#
-
# ===== Options
-
#
-
# * <tt>:if</tt> - A symbol naming an instance method or a proc; the
-
# callback will be called only when it returns a +true+ value.
-
# * <tt>:unless</tt> - A symbol naming an instance method or a proc; the
-
# callback will be called only when it returns a +false+ value.
-
# * <tt>:prepend</tt> - If +true+, the callback will be prepended to the
-
# existing chain rather than appended.
-
1
def set_callback(name, *filter_list, &block)
-
2233
mapped = nil
-
-
2233
__update_callbacks(name, filter_list, block) do |target, chain, type, filters, options|
-
mapped ||= filters.map do |filter|
-
2233
Callback.new(chain, filter, type, options.dup, self)
-
2957
end
-
-
2957
filters.each do |filter|
-
24085
chain.delete_if {|c| c.matches?(type, filter) }
-
end
-
-
2957
options[:prepend] ? chain.unshift(*(mapped.reverse)) : chain.push(*mapped)
-
-
2957
target.send("_#{name}_callbacks=", chain)
-
end
-
end
-
-
# Skip a previously set callback. Like +set_callback+, <tt>:if</tt> or
-
# <tt>:unless</tt> options may be passed in order to control when the
-
# callback is skipped.
-
#
-
# class Writer < Person
-
# skip_callback :validate, :before, :check_membership, if: -> { self.age > 18 }
-
# end
-
1
def skip_callback(name, *filter_list, &block)
-
__update_callbacks(name, filter_list, block) do |target, chain, type, filters, options|
-
filters.each do |filter|
-
filter = chain.find {|c| c.matches?(type, filter) }
-
-
if filter && options.any?
-
new_filter = filter.clone(chain, self)
-
chain.insert(chain.index(filter), new_filter)
-
new_filter.recompile!(options)
-
end
-
-
chain.delete(filter)
-
end
-
target.send("_#{name}_callbacks=", chain)
-
end
-
end
-
-
# Remove all set callbacks for the given event.
-
1
def reset_callbacks(symbol)
-
144
callbacks = send("_#{symbol}_callbacks")
-
-
144
ActiveSupport::DescendantsTracker.descendants(self).each do |target|
-
1182
chain = target.send("_#{symbol}_callbacks").dup
-
1776
callbacks.each { |c| chain.delete(c) }
-
1182
target.send("_#{symbol}_callbacks=", chain)
-
1182
target.__reset_runner(symbol)
-
end
-
-
144
self.send("_#{symbol}_callbacks=", callbacks.dup.clear)
-
-
144
__reset_runner(symbol)
-
end
-
-
# Define sets of events in the object lifecycle that support callbacks.
-
#
-
# define_callbacks :validate
-
# define_callbacks :initialize, :save, :destroy
-
#
-
# ===== Options
-
#
-
# * <tt>:terminator</tt> - Determines when a before filter will halt the
-
# callback chain, preventing following callbacks from being called and
-
# the event from being triggered. This is a string to be eval'ed. The
-
# result of the callback is available in the +result+ variable.
-
#
-
# define_callbacks :validate, terminator: 'result == false'
-
#
-
# In this example, if any before validate callbacks returns +false+,
-
# other callbacks are not executed. Defaults to +false+, meaning no value
-
# halts the chain.
-
#
-
# * <tt>:skip_after_callbacks_if_terminated</tt> - Determines if after
-
# callbacks should be terminated by the <tt>:terminator</tt> option. By
-
# default after callbacks executed no matter if callback chain was
-
# terminated or not. Option makes sense only when <tt>:terminator</tt>
-
# option is specified.
-
#
-
# * <tt>:scope</tt> - Indicates which methods should be executed when an
-
# object is used as a callback.
-
#
-
# class Audit
-
# def before(caller)
-
# puts 'Audit: before is called'
-
# end
-
#
-
# def before_save(caller)
-
# puts 'Audit: before_save is called'
-
# end
-
# end
-
#
-
# class Account
-
# include ActiveSupport::Callbacks
-
#
-
# define_callbacks :save
-
# set_callback :save, :before, Audit.new
-
#
-
# def save
-
# run_callbacks :save do
-
# puts 'save in main'
-
# end
-
# end
-
# end
-
#
-
# In the above case whenever you save an account the method
-
# <tt>Audit#before</tt> will be called. On the other hand
-
#
-
# define_callbacks :save, scope: [:kind, :name]
-
#
-
# would trigger <tt>Audit#before_save</tt> instead. That's constructed
-
# by calling <tt>#{kind}_#{name}</tt> on the given instance. In this
-
# case "kind" is "before" and "name" is "save". In this context +:kind+
-
# and +:name+ have special meanings: +:kind+ refers to the kind of
-
# callback (before/after/around) and +:name+ refers to the method on
-
# which callbacks are being defined.
-
#
-
# A declaration like
-
#
-
# define_callbacks :save, scope: [:name]
-
#
-
# would call <tt>Audit#save</tt>.
-
1
def define_callbacks(*callbacks)
-
12
config = callbacks.last.is_a?(Hash) ? callbacks.pop : {}
-
12
callbacks.each do |callback|
-
15
class_attribute "_#{callback}_callbacks"
-
15
send("_#{callback}_callbacks=", CallbackChain.new(callback, config))
-
end
-
end
-
end
-
end
-
end
-
1
module ActiveSupport
-
# A typical module looks like this:
-
#
-
# module M
-
# def self.included(base)
-
# base.extend ClassMethods
-
# scope :disabled, -> { where(disabled: true) }
-
# end
-
#
-
# module ClassMethods
-
# ...
-
# end
-
# end
-
#
-
# By using <tt>ActiveSupport::Concern</tt> the above module could instead be
-
# written as:
-
#
-
# require 'active_support/concern'
-
#
-
# module M
-
# extend ActiveSupport::Concern
-
#
-
# included do
-
# scope :disabled, -> { where(disabled: true) }
-
# end
-
#
-
# module ClassMethods
-
# ...
-
# end
-
# end
-
#
-
# Moreover, it gracefully handles module dependencies. Given a +Foo+ module
-
# and a +Bar+ module which depends on the former, we would typically write the
-
# following:
-
#
-
# module Foo
-
# def self.included(base)
-
# base.class_eval do
-
# def self.method_injected_by_foo
-
# ...
-
# end
-
# end
-
# end
-
# end
-
#
-
# module Bar
-
# def self.included(base)
-
# base.method_injected_by_foo
-
# end
-
# end
-
#
-
# class Host
-
# include Foo # We need to include this dependency for Bar
-
# include Bar # Bar is the module that Host really needs
-
# end
-
#
-
# But why should +Host+ care about +Bar+'s dependencies, namely +Foo+? We
-
# could try to hide these from +Host+ directly including +Foo+ in +Bar+:
-
#
-
# module Bar
-
# include Foo
-
# def self.included(base)
-
# base.method_injected_by_foo
-
# end
-
# end
-
#
-
# class Host
-
# include Bar
-
# end
-
#
-
# Unfortunately this won't work, since when +Foo+ is included, its <tt>base</tt>
-
# is the +Bar+ module, not the +Host+ class. With <tt>ActiveSupport::Concern</tt>,
-
# module dependencies are properly resolved:
-
#
-
# require 'active_support/concern'
-
#
-
# module Foo
-
# extend ActiveSupport::Concern
-
# included do
-
# class_eval do
-
# def self.method_injected_by_foo
-
# ...
-
# end
-
# end
-
# end
-
# end
-
#
-
# module Bar
-
# extend ActiveSupport::Concern
-
# include Foo
-
#
-
# included do
-
# self.method_injected_by_foo
-
# end
-
# end
-
#
-
# class Host
-
# include Bar # works, Bar takes care now of its dependencies
-
# end
-
1
module Concern
-
1
def self.extended(base) #:nodoc:
-
51
base.instance_variable_set("@_dependencies", [])
-
end
-
-
1
def append_features(base)
-
136
if base.instance_variable_defined?("@_dependencies")
-
7
base.instance_variable_get("@_dependencies") << self
-
7
return false
-
else
-
129
return false if base < self
-
99
@_dependencies.each { |dep| base.send(:include, dep) }
-
86
super
-
86
base.extend const_get("ClassMethods") if const_defined?("ClassMethods")
-
86
base.class_eval(&@_included_block) if instance_variable_defined?("@_included_block")
-
end
-
end
-
-
1
def included(base = nil, &block)
-
171
if base.nil?
-
35
@_included_block = block
-
else
-
136
super
-
end
-
end
-
end
-
end
-
1
require 'active_support/core_ext/array/wrap'
-
1
require 'active_support/core_ext/array/access'
-
1
require 'active_support/core_ext/array/uniq_by'
-
1
require 'active_support/core_ext/array/conversions'
-
1
require 'active_support/core_ext/array/extract_options'
-
1
require 'active_support/core_ext/array/grouping'
-
1
require 'active_support/core_ext/array/prepend_and_append'
-
1
class Array
-
# Returns the tail of the array from +position+.
-
#
-
# %w( a b c d ).from(0) # => ["a", "b", "c", "d"]
-
# %w( a b c d ).from(2) # => ["c", "d"]
-
# %w( a b c d ).from(10) # => []
-
# %w().from(0) # => []
-
1
def from(position)
-
self[position, length] || []
-
end
-
-
# Returns the beginning of the array up to +position+.
-
#
-
# %w( a b c d ).to(0) # => ["a"]
-
# %w( a b c d ).to(2) # => ["a", "b", "c"]
-
# %w( a b c d ).to(10) # => ["a", "b", "c", "d"]
-
# %w().to(0) # => []
-
1
def to(position)
-
first position + 1
-
end
-
-
# Equal to <tt>self[1]</tt>.
-
#
-
# %w( a b c d e).second # => "b"
-
1
def second
-
2
self[1]
-
end
-
-
# Equal to <tt>self[2]</tt>.
-
#
-
# %w( a b c d e).third # => "c"
-
1
def third
-
self[2]
-
end
-
-
# Equal to <tt>self[3]</tt>.
-
#
-
# %w( a b c d e).fourth # => "d"
-
1
def fourth
-
self[3]
-
end
-
-
# Equal to <tt>self[4]</tt>.
-
#
-
# %w( a b c d e).fifth # => "e"
-
1
def fifth
-
self[4]
-
end
-
-
# Equal to <tt>self[41]</tt>. Also known as accessing "the reddit".
-
1
def forty_two
-
self[41]
-
end
-
end
-
1
require 'active_support/xml_mini'
-
1
require 'active_support/core_ext/hash/keys'
-
1
require 'active_support/core_ext/string/inflections'
-
1
require 'active_support/core_ext/object/to_param'
-
1
require 'active_support/core_ext/object/to_query'
-
-
1
class Array
-
# Converts the array to a comma-separated sentence where the last element is
-
# joined by the connector word.
-
#
-
# You can pass the following options to change the default behaviour. If you
-
# pass an option key that doesn't exist in the list below, it will raise an
-
# <tt>ArgumentError</tt>.
-
#
-
# Options:
-
#
-
# * <tt>:words_connector</tt> - The sign or word used to join the elements
-
# in arrays with two or more elements (default: ", ").
-
# * <tt>:two_words_connector</tt> - The sign or word used to join the elements
-
# in arrays with two elements (default: " and ").
-
# * <tt>:last_word_connector</tt> - The sign or word used to join the last element
-
# in arrays with three or more elements (default: ", and ").
-
# * <tt>:locale</tt> - If +i18n+ is available, you can set a locale and use
-
# the connector options defined on the 'support.array' namespace in the
-
# corresponding dictionary file.
-
#
-
# [].to_sentence # => ""
-
# ['one'].to_sentence # => "one"
-
# ['one', 'two'].to_sentence # => "one and two"
-
# ['one', 'two', 'three'].to_sentence # => "one, two, and three"
-
#
-
# ['one', 'two'].to_sentence(passing: 'invalid option')
-
# # => ArgumentError: Unknown key :passing
-
#
-
# ['one', 'two'].to_sentence(two_words_connector: '-')
-
# # => "one-two"
-
#
-
# ['one', 'two', 'three'].to_sentence(words_connector: ' or ', last_word_connector: ' or at least ')
-
# # => "one or two or at least three"
-
#
-
# Examples using <tt>:locale</tt> option:
-
#
-
# # Given this locale dictionary:
-
# #
-
# # es:
-
# # support:
-
# # array:
-
# # words_connector: " o "
-
# # two_words_connector: " y "
-
# # last_word_connector: " o al menos "
-
#
-
# ['uno', 'dos'].to_sentence(locale: :es)
-
# # => "uno y dos"
-
#
-
# ['uno', 'dos', 'tres'].to_sentence(locale: :es)
-
# # => "uno o dos o al menos tres"
-
1
def to_sentence(options = {})
-
options.assert_valid_keys(:words_connector, :two_words_connector, :last_word_connector, :locale)
-
-
default_connectors = {
-
:words_connector => ', ',
-
:two_words_connector => ' and ',
-
:last_word_connector => ', and '
-
}
-
if defined?(I18n)
-
i18n_connectors = I18n.translate(:'support.array', locale: options[:locale], default: {})
-
default_connectors.merge!(i18n_connectors)
-
end
-
options = default_connectors.merge!(options)
-
-
case length
-
when 0
-
''
-
when 1
-
self[0].to_s.dup
-
when 2
-
"#{self[0]}#{options[:two_words_connector]}#{self[1]}"
-
else
-
"#{self[0...-1].join(options[:words_connector])}#{options[:last_word_connector]}#{self[-1]}"
-
end
-
end
-
-
# Converts a collection of elements into a formatted string by calling
-
# <tt>to_s</tt> on all elements and joining them. Having this model:
-
#
-
# class Blog < ActiveRecord::Base
-
# def to_s
-
# title
-
# end
-
# end
-
#
-
# Blog.all.map(&:title) #=> ["First Post", "Second Post", "Third post"]
-
#
-
# <tt>to_formatted_s</tt> shows us:
-
#
-
# Blog.all.to_formatted_s # => "First PostSecond PostThird Post"
-
#
-
# Adding in the <tt>:db</tt> argument as the format yields a comma separated
-
# id list:
-
#
-
# Blog.all.to_formatted_s(:db) # => "1,2,3"
-
1
def to_formatted_s(format = :default)
-
17
case format
-
when :db
-
if empty?
-
'null'
-
else
-
collect { |element| element.id }.join(',')
-
end
-
else
-
17
to_default_s
-
end
-
end
-
1
alias_method :to_default_s, :to_s
-
1
alias_method :to_s, :to_formatted_s
-
-
# Returns a string that represents the array in XML by invoking +to_xml+
-
# on each element. Active Record collections delegate their representation
-
# in XML to this method.
-
#
-
# All elements are expected to respond to +to_xml+, if any of them does
-
# not then an exception is raised.
-
#
-
# The root node reflects the class name of the first element in plural
-
# if all elements belong to the same type and that's not Hash:
-
#
-
# customer.projects.to_xml
-
#
-
# <?xml version="1.0" encoding="UTF-8"?>
-
# <projects type="array">
-
# <project>
-
# <amount type="decimal">20000.0</amount>
-
# <customer-id type="integer">1567</customer-id>
-
# <deal-date type="date">2008-04-09</deal-date>
-
# ...
-
# </project>
-
# <project>
-
# <amount type="decimal">57230.0</amount>
-
# <customer-id type="integer">1567</customer-id>
-
# <deal-date type="date">2008-04-15</deal-date>
-
# ...
-
# </project>
-
# </projects>
-
#
-
# Otherwise the root element is "objects":
-
#
-
# [{ foo: 1, bar: 2}, { baz: 3}].to_xml
-
#
-
# <?xml version="1.0" encoding="UTF-8"?>
-
# <objects type="array">
-
# <object>
-
# <bar type="integer">2</bar>
-
# <foo type="integer">1</foo>
-
# </object>
-
# <object>
-
# <baz type="integer">3</baz>
-
# </object>
-
# </objects>
-
#
-
# If the collection is empty the root element is "nil-classes" by default:
-
#
-
# [].to_xml
-
#
-
# <?xml version="1.0" encoding="UTF-8"?>
-
# <nil-classes type="array"/>
-
#
-
# To ensure a meaningful root element use the <tt>:root</tt> option:
-
#
-
# customer_with_no_projects.projects.to_xml(root: 'projects')
-
#
-
# <?xml version="1.0" encoding="UTF-8"?>
-
# <projects type="array"/>
-
#
-
# By default name of the node for the children of root is <tt>root.singularize</tt>.
-
# You can change it with the <tt>:children</tt> option.
-
#
-
# The +options+ hash is passed downwards:
-
#
-
# Message.all.to_xml(skip_types: true)
-
#
-
# <?xml version="1.0" encoding="UTF-8"?>
-
# <messages>
-
# <message>
-
# <created-at>2008-03-07T09:58:18+01:00</created-at>
-
# <id>1</id>
-
# <name>1</name>
-
# <updated-at>2008-03-07T09:58:18+01:00</updated-at>
-
# <user-id>1</user-id>
-
# </message>
-
# </messages>
-
#
-
1
def to_xml(options = {})
-
9
require 'active_support/builder' unless defined?(Builder)
-
-
9
options = options.dup
-
9
options[:indent] ||= 2
-
9
options[:builder] ||= Builder::XmlMarkup.new(indent: options[:indent])
-
9
options[:root] ||= \
-
14
if first.class != Hash && all? { |e| e.is_a?(first.class) }
-
7
underscored = ActiveSupport::Inflector.underscore(first.class.name)
-
7
ActiveSupport::Inflector.pluralize(underscored).tr('/', '_')
-
else
-
1
'objects'
-
end
-
-
9
builder = options[:builder]
-
9
builder.instruct! unless options.delete(:skip_instruct)
-
-
9
root = ActiveSupport::XmlMini.rename_key(options[:root].to_s, options)
-
9
children = options.delete(:children) || root.singularize
-
9
attributes = options[:skip_types] ? {} : { type: 'array' }
-
-
9
if empty?
-
2
builder.tag!(root, attributes)
-
else
-
7
builder.tag!(root, attributes) do
-
23
each { |value| ActiveSupport::XmlMini.to_tag(children, value, options) }
-
7
yield builder if block_given?
-
end
-
end
-
end
-
end
-
1
class Hash
-
# By default, only instances of Hash itself are extractable.
-
# Subclasses of Hash may implement this method and return
-
# true to declare themselves as extractable. If a Hash
-
# is extractable, Array#extract_options! pops it from
-
# the Array when it is the last element of the Array.
-
1
def extractable_options?
-
492
instance_of?(Hash)
-
end
-
end
-
-
1
class Array
-
# Extracts options from a set of arguments. Removes and returns the last
-
# element in the array if it's a hash, otherwise returns a blank hash.
-
#
-
# def options(*args)
-
# args.extract_options!
-
# end
-
#
-
# options(1, 2) # => {}
-
# options(1, 2, a: :b) # => {:a=>:b}
-
1
def extract_options!
-
7542
if last.is_a?(Hash) && last.extractable_options?
-
492
pop
-
else
-
7050
{}
-
end
-
end
-
end
-
1
class Array
-
# Splits or iterates over the array in groups of size +number+,
-
# padding any remaining slots with +fill_with+ unless it is +false+.
-
#
-
# %w(1 2 3 4 5 6 7 8 9 10).in_groups_of(3) {|group| p group}
-
# ["1", "2", "3"]
-
# ["4", "5", "6"]
-
# ["7", "8", "9"]
-
# ["10", nil, nil]
-
#
-
# %w(1 2 3 4 5).in_groups_of(2, ' ') {|group| p group}
-
# ["1", "2"]
-
# ["3", "4"]
-
# ["5", " "]
-
#
-
# %w(1 2 3 4 5).in_groups_of(2, false) {|group| p group}
-
# ["1", "2"]
-
# ["3", "4"]
-
# ["5"]
-
1
def in_groups_of(number, fill_with = nil)
-
if fill_with == false
-
collection = self
-
else
-
# size % number gives how many extra we have;
-
# subtracting from number gives how many to add;
-
# modulo number ensures we don't add group of just fill.
-
padding = (number - size % number) % number
-
collection = dup.concat([fill_with] * padding)
-
end
-
-
if block_given?
-
collection.each_slice(number) { |slice| yield(slice) }
-
else
-
groups = []
-
collection.each_slice(number) { |group| groups << group }
-
groups
-
end
-
end
-
-
# Splits or iterates over the array in +number+ of groups, padding any
-
# remaining slots with +fill_with+ unless it is +false+.
-
#
-
# %w(1 2 3 4 5 6 7 8 9 10).in_groups(3) {|group| p group}
-
# ["1", "2", "3", "4"]
-
# ["5", "6", "7", nil]
-
# ["8", "9", "10", nil]
-
#
-
# %w(1 2 3 4 5 6 7 8 9 10).in_groups(3, ' ') {|group| p group}
-
# ["1", "2", "3", "4"]
-
# ["5", "6", "7", " "]
-
# ["8", "9", "10", " "]
-
#
-
# %w(1 2 3 4 5 6 7).in_groups(3, false) {|group| p group}
-
# ["1", "2", "3"]
-
# ["4", "5"]
-
# ["6", "7"]
-
1
def in_groups(number, fill_with = nil)
-
# size / number gives minor group size;
-
# size % number gives how many objects need extra accommodation;
-
# each group hold either division or division + 1 items.
-
division = size / number
-
modulo = size % number
-
-
# create a new array avoiding dup
-
groups = []
-
start = 0
-
-
number.times do |index|
-
length = division + (modulo > 0 && modulo > index ? 1 : 0)
-
padding = fill_with != false &&
-
modulo > 0 && length == division ? 1 : 0
-
groups << slice(start, length).concat([fill_with] * padding)
-
start += length
-
end
-
-
if block_given?
-
groups.each { |g| yield(g) }
-
else
-
groups
-
end
-
end
-
-
# Divides the array into one or more subarrays based on a delimiting +value+
-
# or the result of an optional block.
-
#
-
# [1, 2, 3, 4, 5].split(3) # => [[1, 2], [4, 5]]
-
# (1..10).to_a.split { |i| i % 3 == 0 } # => [[1, 2], [4, 5], [7, 8], [10]]
-
1
def split(value = nil, &block)
-
inject([[]]) do |results, element|
-
if block && block.call(element) || value == element
-
results << []
-
else
-
results.last << element
-
end
-
-
results
-
end
-
end
-
end
-
1
class Array
-
# The human way of thinking about adding stuff to the end of a list is with append
-
1
alias_method :append, :<<
-
-
# The human way of thinking about adding stuff to the beginning of a list is with prepend
-
1
alias_method :prepend, :unshift
-
end
-
1
class Array
-
# *DEPRECATED*: Use +Array#uniq+ instead.
-
#
-
# Returns a unique array based on the criteria in the block.
-
#
-
# [1, 2, 3, 4].uniq_by { |i| i.odd? } # => [1, 2]
-
1
def uniq_by(&block)
-
ActiveSupport::Deprecation.warn 'uniq_by is deprecated. Use Array#uniq instead'
-
uniq(&block)
-
end
-
-
# *DEPRECATED*: Use +Array#uniq!+ instead.
-
#
-
# Same as +uniq_by+, but modifies +self+.
-
1
def uniq_by!(&block)
-
ActiveSupport::Deprecation.warn 'uniq_by! is deprecated. Use Array#uniq! instead'
-
uniq!(&block)
-
end
-
end
-
1
class Array
-
# Wraps its argument in an array unless it is already an array (or array-like).
-
#
-
# Specifically:
-
#
-
# * If the argument is +nil+ an empty list is returned.
-
# * Otherwise, if the argument responds to +to_ary+ it is invoked, and its result returned.
-
# * Otherwise, returns an array with the argument as its single element.
-
#
-
# Array.wrap(nil) # => []
-
# Array.wrap([1, 2, 3]) # => [1, 2, 3]
-
# Array.wrap(0) # => [0]
-
#
-
# This method is similar in purpose to <tt>Kernel#Array</tt>, but there are some differences:
-
#
-
# * If the argument responds to +to_ary+ the method is invoked. <tt>Kernel#Array</tt>
-
# moves on to try +to_a+ if the returned value is +nil+, but <tt>Array.wrap</tt> returns
-
# such a +nil+ right away.
-
# * If the returned value from +to_ary+ is neither +nil+ nor an +Array+ object, <tt>Kernel#Array</tt>
-
# raises an exception, while <tt>Array.wrap</tt> does not, it just returns the value.
-
# * It does not call +to_a+ on the argument, though special-cases +nil+ to return an empty array.
-
#
-
# The last point is particularly worth comparing for some enumerables:
-
#
-
# Array(foo: :bar) # => [[:foo, :bar]]
-
# Array.wrap(foo: :bar) # => [{:foo=>:bar}]
-
#
-
# There's also a related idiom that uses the splat operator:
-
#
-
# [*object]
-
#
-
# which for +nil+ returns <tt>[nil]</tt> (Ruby 1.8.7) or <tt>[]</tt> (Ruby
-
# 1.9), and calls to <tt>Array(object)</tt> otherwise.
-
#
-
# Thus, in this case the behavior may be different for +nil+, and the differences with
-
# <tt>Kernel#Array</tt> explained above apply to the rest of <tt>object</tt>s.
-
1
def self.wrap(object)
-
1409
if object.nil?
-
15
[]
-
1394
elsif object.respond_to?(:to_ary)
-
799
object.to_ary || [object]
-
else
-
595
[object]
-
end
-
end
-
end
-
1
require 'benchmark'
-
-
1
class << Benchmark
-
1
def ms
-
8
1000 * realtime { yield }
-
end
-
end
-
1
require 'active_support/core_ext/big_decimal/conversions'
-
1
require 'bigdecimal'
-
1
require 'yaml'
-
-
1
class BigDecimal
-
1
YAML_MAPPING = { 'Infinity' => '.Inf', '-Infinity' => '-.Inf', 'NaN' => '.NaN' }
-
-
1
def encode_with(coder)
-
string = to_s
-
coder.represent_scalar(nil, YAML_MAPPING[string] || string)
-
end
-
-
# Backport this method if it doesn't exist
-
1
unless method_defined?(:to_d)
-
def to_d
-
self
-
end
-
end
-
-
1
DEFAULT_STRING_FORMAT = 'F'
-
1
def to_formatted_s(*args)
-
66
if args[0].is_a?(Symbol)
-
super
-
else
-
66
format = args[0] || DEFAULT_STRING_FORMAT
-
66
_original_to_s(format)
-
end
-
end
-
1
alias_method :_original_to_s, :to_s
-
1
alias_method :to_s, :to_formatted_s
-
end
-
1
require 'active_support/core_ext/kernel/singleton_class'
-
1
require 'active_support/core_ext/module/remove_method'
-
1
require 'active_support/core_ext/array/extract_options'
-
-
1
class Class
-
# Declare a class-level attribute whose value is inheritable by subclasses.
-
# Subclasses can change their own value and it will not impact parent class.
-
#
-
# class Base
-
# class_attribute :setting
-
# end
-
#
-
# class Subclass < Base
-
# end
-
#
-
# Base.setting = true
-
# Subclass.setting # => true
-
# Subclass.setting = false
-
# Subclass.setting # => false
-
# Base.setting # => true
-
#
-
# In the above case as long as Subclass does not assign a value to setting
-
# by performing <tt>Subclass.setting = _something_ </tt>, <tt>Subclass.setting</tt>
-
# would read value assigned to parent class. Once Subclass assigns a value then
-
# the value assigned by Subclass would be returned.
-
#
-
# This matches normal Ruby method inheritance: think of writing an attribute
-
# on a subclass as overriding the reader method. However, you need to be aware
-
# when using +class_attribute+ with mutable structures as +Array+ or +Hash+.
-
# In such cases, you don't want to do changes in places but use setters:
-
#
-
# Base.setting = []
-
# Base.setting # => []
-
# Subclass.setting # => []
-
#
-
# # Appending in child changes both parent and child because it is the same object:
-
# Subclass.setting << :foo
-
# Base.setting # => [:foo]
-
# Subclass.setting # => [:foo]
-
#
-
# # Use setters to not propagate changes:
-
# Base.setting = []
-
# Subclass.setting += [:foo]
-
# Base.setting # => []
-
# Subclass.setting # => [:foo]
-
#
-
# For convenience, a query method is defined as well:
-
#
-
# Subclass.setting? # => false
-
#
-
# Instances may overwrite the class value in the same way:
-
#
-
# Base.setting = true
-
# object = Base.new
-
# object.setting # => true
-
# object.setting = false
-
# object.setting # => false
-
# Base.setting # => true
-
#
-
# To opt out of the instance reader method, pass <tt>instance_reader: false</tt>.
-
#
-
# object.setting # => NoMethodError
-
# object.setting? # => NoMethodError
-
#
-
# To opt out of the instance writer method, pass <tt>instance_writer: false</tt>.
-
#
-
# object.setting = false # => NoMethodError
-
#
-
# To opt out of both instance methods, pass <tt>instance_accessor: false</tt>.
-
1
def class_attribute(*attrs)
-
1549
options = attrs.extract_options!
-
1549
instance_reader = options.fetch(:instance_accessor, true) && options.fetch(:instance_reader, true)
-
1549
instance_writer = options.fetch(:instance_accessor, true) && options.fetch(:instance_writer, true)
-
-
1549
attrs.each do |name|
-
1552
class_eval <<-RUBY, __FILE__, __LINE__ + 1
-
def self.#{name}() nil end
-
def self.#{name}?() !!#{name} end
-
-
def self.#{name}=(val)
-
singleton_class.class_eval do
-
remove_possible_method(:#{name})
-
define_method(:#{name}) { val }
-
end
-
-
if singleton_class?
-
class_eval do
-
remove_possible_method(:#{name})
-
def #{name}
-
defined?(@#{name}) ? @#{name} : singleton_class.#{name}
-
end
-
end
-
end
-
val
-
end
-
-
if instance_reader
-
remove_possible_method :#{name}
-
def #{name}
-
defined?(@#{name}) ? @#{name} : self.class.#{name}
-
end
-
-
def #{name}?
-
!!#{name}
-
end
-
end
-
RUBY
-
-
1552
attr_writer name if instance_writer
-
end
-
end
-
-
1
private
-
1
def singleton_class?
-
8874
ancestors.first != self
-
end
-
end
-
1
require 'active_support/core_ext/array/extract_options'
-
-
# Extends the class object with class and instance accessors for class attributes,
-
# just like the native attr* accessors for instance attributes.
-
1
class Class
-
# Defines a class attribute if it's not defined and creates a reader method that
-
# returns the attribute value.
-
#
-
# class Person
-
# cattr_reader :hair_colors
-
# end
-
#
-
# Person.class_variable_set("@@hair_colors", [:brown, :black])
-
# Person.hair_colors # => [:brown, :black]
-
# Person.new.hair_colors # => [:brown, :black]
-
#
-
# The attribute name must be a valid method name in Ruby.
-
#
-
# class Person
-
# cattr_reader :"1_Badname "
-
# end
-
# # => NameError: invalid attribute name
-
#
-
# If you want to opt out the instance reader method, you can pass <tt>instance_reader: false</tt>
-
# or <tt>instance_accessor: false</tt>.
-
#
-
# class Person
-
# cattr_reader :hair_colors, instance_reader: false
-
# end
-
#
-
# Person.new.hair_colors # => NoMethodError
-
1
def cattr_reader(*syms)
-
7
options = syms.extract_options!
-
7
syms.each do |sym|
-
7
raise NameError.new('invalid attribute name') unless sym =~ /^[_A-Za-z]\w*$/
-
7
class_eval(<<-EOS, __FILE__, __LINE__ + 1)
-
unless defined? @@#{sym}
-
@@#{sym} = nil
-
end
-
-
def self.#{sym}
-
@@#{sym}
-
end
-
EOS
-
-
7
unless options[:instance_reader] == false || options[:instance_accessor] == false
-
7
class_eval(<<-EOS, __FILE__, __LINE__ + 1)
-
def #{sym}
-
@@#{sym}
-
end
-
EOS
-
end
-
end
-
end
-
-
# Defines a class attribute if it's not defined and creates a writer method to allow
-
# assignment to the attribute.
-
#
-
# class Person
-
# cattr_writer :hair_colors
-
# end
-
#
-
# Person.hair_colors = [:brown, :black]
-
# Person.class_variable_get("@@hair_colors") # => [:brown, :black]
-
# Person.new.hair_colors = [:blonde, :red]
-
# Person.class_variable_get("@@hair_colors") # => [:blonde, :red]
-
#
-
# The attribute name must be a valid method name in Ruby.
-
#
-
# class Person
-
# cattr_writer :"1_Badname "
-
# end
-
# # => NameError: invalid attribute name
-
#
-
# If you want to opt out the instance writer method, pass <tt>instance_writer: false</tt>
-
# or <tt>instance_accessor: false</tt>.
-
#
-
# class Person
-
# cattr_writer :hair_colors, instance_writer: false
-
# end
-
#
-
# Person.new.hair_colors = [:blonde, :red] # => NoMethodError
-
#
-
# Also, you can pass a block to set up the attribute with a default value.
-
#
-
# class Person
-
# cattr_writer :hair_colors do
-
# [:brown, :black, :blonde, :red]
-
# end
-
# end
-
#
-
# Person.class_variable_get("@@hair_colors") # => [:brown, :black, :blonde, :red]
-
1
def cattr_writer(*syms)
-
6
options = syms.extract_options!
-
6
syms.each do |sym|
-
6
raise NameError.new('invalid attribute name') unless sym =~ /^[_A-Za-z]\w*$/
-
6
class_eval(<<-EOS, __FILE__, __LINE__ + 1)
-
unless defined? @@#{sym}
-
@@#{sym} = nil
-
end
-
-
def self.#{sym}=(obj)
-
@@#{sym} = obj
-
end
-
EOS
-
-
6
unless options[:instance_writer] == false || options[:instance_accessor] == false
-
6
class_eval(<<-EOS, __FILE__, __LINE__ + 1)
-
def #{sym}=(obj)
-
@@#{sym} = obj
-
end
-
EOS
-
end
-
6
send("#{sym}=", yield) if block_given?
-
end
-
end
-
-
# Defines both class and instance accessors for class attributes.
-
#
-
# class Person
-
# cattr_accessor :hair_colors
-
# end
-
#
-
# Person.hair_colors = [:brown, :black, :blonde, :red]
-
# Person.hair_colors # => [:brown, :black, :blonde, :red]
-
# Person.new.hair_colors # => [:brown, :black, :blonde, :red]
-
#
-
# If a subclass changes the value then that would also change the value for
-
# parent class. Similarly if parent class changes the value then that would
-
# change the value of subclasses too.
-
#
-
# class Male < Person
-
# end
-
#
-
# Male.hair_colors << :blue
-
# Person.hair_colors # => [:brown, :black, :blonde, :red, :blue]
-
#
-
# To opt out of the instance writer method, pass <tt>instance_writer: false</tt>.
-
# To opt out of the instance reader method, pass <tt>instance_reader: false</tt>.
-
#
-
# class Person
-
# cattr_accessor :hair_colors, instance_writer: false, instance_reader: false
-
# end
-
#
-
# Person.new.hair_colors = [:brown] # => NoMethodError
-
# Person.new.hair_colors # => NoMethodError
-
#
-
# Or pass <tt>instance_accessor: false</tt>, to opt out both instance methods.
-
#
-
# class Person
-
# cattr_accessor :hair_colors, instance_accessor: false
-
# end
-
#
-
# Person.new.hair_colors = [:brown] # => NoMethodError
-
# Person.new.hair_colors # => NoMethodError
-
#
-
# Also you can pass a block to set up the attribute with a default value.
-
#
-
# class Person
-
# cattr_accessor :hair_colors do
-
# [:brown, :black, :blonde, :red]
-
# end
-
# end
-
#
-
# Person.class_variable_get("@@hair_colors") #=> [:brown, :black, :blonde, :red]
-
1
def cattr_accessor(*syms, &blk)
-
6
cattr_reader(*syms)
-
6
cattr_writer(*syms, &blk)
-
end
-
end
-
1
require 'active_support/core_ext/kernel/singleton_class'
-
1
require 'active_support/core_ext/module/remove_method'
-
-
1
class Class
-
1
def superclass_delegating_accessor(name, options = {})
-
# Create private _name and _name= methods that can still be used if the public
-
# methods are overridden. This allows
-
_superclass_delegating_accessor("_#{name}")
-
-
# Generate the public methods name, name=, and name?
-
# These methods dispatch to the private _name, and _name= methods, making them
-
# overridable
-
singleton_class.send(:define_method, name) { send("_#{name}") }
-
singleton_class.send(:define_method, "#{name}?") { !!send("_#{name}") }
-
singleton_class.send(:define_method, "#{name}=") { |value| send("_#{name}=", value) }
-
-
# If an instance_reader is needed, generate methods for name and name= on the
-
# class itself, so instances will be able to see them
-
define_method(name) { send("_#{name}") } if options[:instance_reader] != false
-
define_method("#{name}?") { !!send("#{name}") } if options[:instance_reader] != false
-
end
-
-
1
private
-
# Take the object being set and store it in a method. This gives us automatic
-
# inheritance behavior, without having to store the object in an instance
-
# variable and look up the superclass chain manually.
-
1
def _stash_object_in_method(object, method, instance_reader = true)
-
singleton_class.remove_possible_method(method)
-
singleton_class.send(:define_method, method) { object }
-
remove_possible_method(method)
-
define_method(method) { object } if instance_reader
-
end
-
-
1
def _superclass_delegating_accessor(name, options = {})
-
singleton_class.send(:define_method, "#{name}=") do |value|
-
_stash_object_in_method(value, name, options[:instance_reader] != false)
-
end
-
send("#{name}=", nil)
-
end
-
end
-
1
require 'active_support/core_ext/object/acts_like'
-
-
1
class Date
-
# Duck-types as a Date-like class. See Object#acts_like?.
-
1
def acts_like_date?
-
true
-
end
-
end
-
1
require 'date'
-
1
require 'active_support/duration'
-
1
require 'active_support/core_ext/object/acts_like'
-
1
require 'active_support/core_ext/date/zones'
-
1
require 'active_support/core_ext/time/zones'
-
1
require 'active_support/core_ext/date_and_time/calculations'
-
-
1
class Date
-
1
include DateAndTime::Calculations
-
-
1
@beginning_of_week_default = nil
-
-
1
class << self
-
1
attr_accessor :beginning_of_week_default
-
-
# Returns the week start (e.g. :monday) for the current request, if this has been set (via Date.beginning_of_week=).
-
# If <tt>Date.beginning_of_week</tt> has not been set for the current request, returns the week start specified in <tt>config.beginning_of_week</tt>.
-
# If no config.beginning_of_week was specified, returns :monday.
-
1
def beginning_of_week
-
Thread.current[:beginning_of_week] || beginning_of_week_default || :monday
-
end
-
-
# Sets <tt>Date.beginning_of_week</tt> to a week start (e.g. :monday) for current request/thread.
-
#
-
# This method accepts any of the following day symbols:
-
# :monday, :tuesday, :wednesday, :thursday, :friday, :saturday, :sunday
-
1
def beginning_of_week=(week_start)
-
Thread.current[:beginning_of_week] = find_beginning_of_week!(week_start)
-
end
-
-
# Returns week start day symbol (e.g. :monday), or raises an ArgumentError for invalid day symbol.
-
1
def find_beginning_of_week!(week_start)
-
raise ArgumentError, "Invalid beginning of week: #{week_start}" unless ::Date::DAYS_INTO_WEEK.key?(week_start)
-
week_start
-
end
-
-
# Returns a new Date representing the date 1 day ago (i.e. yesterday's date).
-
1
def yesterday
-
::Date.current.yesterday
-
end
-
-
# Returns a new Date representing the date 1 day after today (i.e. tomorrow's date).
-
1
def tomorrow
-
::Date.current.tomorrow
-
end
-
-
# Returns Time.zone.today when <tt>Time.zone</tt> or <tt>config.time_zone</tt> are set, otherwise just returns Date.today.
-
1
def current
-
::Time.zone ? ::Time.zone.today : ::Date.today
-
end
-
end
-
-
# Converts Date to a Time (or DateTime if necessary) with the time portion set to the beginning of the day (0:00)
-
# and then subtracts the specified number of seconds.
-
1
def ago(seconds)
-
to_time_in_current_zone.since(-seconds)
-
end
-
-
# Converts Date to a Time (or DateTime if necessary) with the time portion set to the beginning of the day (0:00)
-
# and then adds the specified number of seconds
-
1
def since(seconds)
-
to_time_in_current_zone.since(seconds)
-
end
-
1
alias :in :since
-
-
# Converts Date to a Time (or DateTime if necessary) with the time portion set to the beginning of the day (0:00)
-
1
def beginning_of_day
-
to_time_in_current_zone
-
end
-
1
alias :midnight :beginning_of_day
-
1
alias :at_midnight :beginning_of_day
-
1
alias :at_beginning_of_day :beginning_of_day
-
-
# Converts Date to a Time (or DateTime if necessary) with the time portion set to the end of the day (23:59:59)
-
1
def end_of_day
-
to_time_in_current_zone.end_of_day
-
end
-
-
1
def plus_with_duration(other) #:nodoc:
-
35
if ActiveSupport::Duration === other
-
other.since(self)
-
else
-
35
plus_without_duration(other)
-
end
-
end
-
1
alias_method :plus_without_duration, :+
-
1
alias_method :+, :plus_with_duration
-
-
1
def minus_with_duration(other) #:nodoc:
-
if ActiveSupport::Duration === other
-
plus_with_duration(-other)
-
else
-
minus_without_duration(other)
-
end
-
end
-
1
alias_method :minus_without_duration, :-
-
1
alias_method :-, :minus_with_duration
-
-
# Provides precise Date calculations for years, months, and days. The +options+ parameter takes a hash with
-
# any of these keys: <tt>:years</tt>, <tt>:months</tt>, <tt>:weeks</tt>, <tt>:days</tt>.
-
1
def advance(options)
-
62
options = options.dup
-
62
d = self
-
62
d = d >> options.delete(:years) * 12 if options[:years]
-
62
d = d >> options.delete(:months) if options[:months]
-
62
d = d + options.delete(:weeks) * 7 if options[:weeks]
-
62
d = d + options.delete(:days) if options[:days]
-
62
d
-
end
-
-
# Returns a new Date where one or more of the elements have been changed according to the +options+ parameter.
-
# The +options+ parameter is a hash with a combination of these keys: <tt>:year</tt>, <tt>:month</tt>, <tt>:day</tt>.
-
#
-
# Date.new(2007, 5, 12).change(day: 1) # => Date.new(2007, 5, 1)
-
# Date.new(2007, 5, 12).change(year: 2005, month: 1) # => Date.new(2005, 1, 12)
-
1
def change(options)
-
::Date.new(
-
options.fetch(:year, year),
-
options.fetch(:month, month),
-
options.fetch(:day, day)
-
)
-
end
-
end
-
1
require 'date'
-
1
require 'active_support/inflector/methods'
-
1
require 'active_support/core_ext/date/zones'
-
1
require 'active_support/core_ext/module/remove_method'
-
-
1
class Date
-
1
DATE_FORMATS = {
-
:short => '%e %b',
-
:long => '%B %e, %Y',
-
:db => '%Y-%m-%d',
-
:number => '%Y%m%d',
-
:long_ordinal => lambda { |date|
-
day_format = ActiveSupport::Inflector.ordinalize(date.day)
-
date.strftime("%B #{day_format}, %Y") # => "April 25th, 2007"
-
},
-
:rfc822 => '%e %b %Y'
-
}
-
-
# Ruby 1.9 has Date#to_time which converts to localtime only.
-
1
remove_possible_method :to_time
-
-
# Ruby 1.9 has Date#xmlschema which converts to a string without the time component.
-
1
remove_possible_method :xmlschema
-
-
# Convert to a formatted string. See DATE_FORMATS for predefined formats.
-
#
-
# This method is aliased to <tt>to_s</tt>.
-
#
-
# date = Date.new(2007, 11, 10) # => Sat, 10 Nov 2007
-
#
-
# date.to_formatted_s(:db) # => "2007-11-10"
-
# date.to_s(:db) # => "2007-11-10"
-
#
-
# date.to_formatted_s(:short) # => "10 Nov"
-
# date.to_formatted_s(:long) # => "November 10, 2007"
-
# date.to_formatted_s(:long_ordinal) # => "November 10th, 2007"
-
# date.to_formatted_s(:rfc822) # => "10 Nov 2007"
-
#
-
# == Adding your own time formats to to_formatted_s
-
# You can add your own formats to the Date::DATE_FORMATS hash.
-
# Use the format name as the hash key and either a strftime string
-
# or Proc instance that takes a date argument as the value.
-
#
-
# # config/initializers/time_formats.rb
-
# Date::DATE_FORMATS[:month_and_year] = '%B %Y'
-
# Date::DATE_FORMATS[:short_ordinal] = ->(date) { date.strftime("%B #{date.day.ordinalize}") }
-
1
def to_formatted_s(format = :default)
-
178
if formatter = DATE_FORMATS[format]
-
174
if formatter.respond_to?(:call)
-
formatter.call(self).to_s
-
else
-
174
strftime(formatter)
-
end
-
else
-
4
to_default_s
-
end
-
end
-
1
alias_method :to_default_s, :to_s
-
1
alias_method :to_s, :to_formatted_s
-
-
# Overrides the default inspect method with a human readable one, e.g., "Mon, 21 Feb 2005"
-
1
def readable_inspect
-
45
strftime('%a, %d %b %Y')
-
end
-
1
alias_method :default_inspect, :inspect
-
1
alias_method :inspect, :readable_inspect
-
-
# Converts a Date instance to a Time, where the time is set to the beginning of the day.
-
# The timezone can be either :local or :utc (default :local).
-
#
-
# date = Date.new(2007, 11, 10) # => Sat, 10 Nov 2007
-
#
-
# date.to_time # => Sat Nov 10 00:00:00 0800 2007
-
# date.to_time(:local) # => Sat Nov 10 00:00:00 0800 2007
-
#
-
# date.to_time(:utc) # => Sat Nov 10 00:00:00 UTC 2007
-
1
def to_time(form = :local)
-
1
::Time.send("#{form}_time", year, month, day)
-
end
-
-
1
def xmlschema
-
1
to_time_in_current_zone.xmlschema
-
end
-
end
-
1
require 'date'
-
1
require 'active_support/core_ext/time/zones'
-
-
1
class Date
-
# Converts Date to a TimeWithZone in the current zone if <tt>Time.zone</tt> or
-
# <tt>Time.zone_default</tt> is set, otherwise converts Date to a Time via
-
# Date#to_time.
-
1
def to_time_in_current_zone
-
1
if ::Time.zone
-
::Time.zone.local(year, month, day)
-
else
-
1
to_time
-
end
-
end
-
end
-
1
module DateAndTime
-
1
module Calculations
-
1
DAYS_INTO_WEEK = {
-
:monday => 0,
-
:tuesday => 1,
-
:wednesday => 2,
-
:thursday => 3,
-
:friday => 4,
-
:saturday => 5,
-
:sunday => 6
-
}
-
-
# Returns a new date/time representing yesterday.
-
1
def yesterday
-
advance(:days => -1)
-
end
-
-
# Returns a new date/time representing tomorrow.
-
1
def tomorrow
-
advance(:days => 1)
-
end
-
-
# Returns true if the date/time is today.
-
1
def today?
-
to_date == ::Date.current
-
end
-
-
# Returns true if the date/time is in the past.
-
1
def past?
-
self < self.class.current
-
end
-
-
# Returns true if the date/time is in the future.
-
1
def future?
-
self > self.class.current
-
end
-
-
# Returns a new date/time the specified number of days ago.
-
1
def days_ago(days)
-
advance(:days => -days)
-
end
-
-
# Returns a new date/time the specified number of days in the future.
-
1
def days_since(days)
-
advance(:days => days)
-
end
-
-
# Returns a new date/time the specified number of weeks ago.
-
1
def weeks_ago(weeks)
-
advance(:weeks => -weeks)
-
end
-
-
# Returns a new date/time the specified number of weeks in the future.
-
1
def weeks_since(weeks)
-
advance(:weeks => weeks)
-
end
-
-
# Returns a new date/time the specified number of months ago.
-
1
def months_ago(months)
-
31
advance(:months => -months)
-
end
-
-
# Returns a new date/time the specified number of months in the future.
-
1
def months_since(months)
-
advance(:months => months)
-
end
-
-
# Returns a new date/time the specified number of years ago.
-
1
def years_ago(years)
-
advance(:years => -years)
-
end
-
-
# Returns a new date/time the specified number of years in the future.
-
1
def years_since(years)
-
advance(:years => years)
-
end
-
-
# Returns a new date/time at the start of the month.
-
# DateTime objects will have a time set to 0:00.
-
1
def beginning_of_month
-
first_hour{ change(:day => 1) }
-
end
-
1
alias :at_beginning_of_month :beginning_of_month
-
-
# Returns a new date/time at the start of the quarter.
-
# Example: 1st January, 1st July, 1st October.
-
# DateTime objects will have a time set to 0:00.
-
1
def beginning_of_quarter
-
first_quarter_month = [10, 7, 4, 1].detect { |m| m <= month }
-
beginning_of_month.change(:month => first_quarter_month)
-
end
-
1
alias :at_beginning_of_quarter :beginning_of_quarter
-
-
# Returns a new date/time at the end of the quarter.
-
# Example: 31st March, 30th June, 30th September.
-
# DateTIme objects will have a time set to 23:59:59.
-
1
def end_of_quarter
-
last_quarter_month = [3, 6, 9, 12].detect { |m| m >= month }
-
beginning_of_month.change(:month => last_quarter_month).end_of_month
-
end
-
1
alias :at_end_of_quarter :end_of_quarter
-
-
# Return a new date/time at the beginning of the year.
-
# Example: 1st January.
-
# DateTime objects will have a time set to 0:00.
-
1
def beginning_of_year
-
change(:month => 1).beginning_of_month
-
end
-
1
alias :at_beginning_of_year :beginning_of_year
-
-
# Returns a new date/time representing the given day in the next week.
-
# Week is assumed to start on +start_day+, default is
-
# +Date.beginning_of_week+ or +config.beginning_of_week+ when set.
-
# DateTime objects have their time set to 0:00.
-
1
def next_week(start_day = Date.beginning_of_week)
-
first_hour{ weeks_since(1).beginning_of_week.days_since(days_span(start_day)) }
-
end
-
-
# Short-hand for months_since(1).
-
1
def next_month
-
months_since(1)
-
end
-
-
# Short-hand for months_since(3)
-
1
def next_quarter
-
months_since(3)
-
end
-
-
# Short-hand for years_since(1).
-
1
def next_year
-
years_since(1)
-
end
-
-
# Returns a new date/time representing the given day in the previous week.
-
# Week is assumed to start on +start_day+, default is
-
# +Date.beginning_of_week+ or +config.beginning_of_week+ when set.
-
# DateTime objects have their time set to 0:00.
-
1
def prev_week(start_day = Date.beginning_of_week)
-
first_hour{ weeks_ago(1).beginning_of_week.days_since(days_span(start_day)) }
-
end
-
1
alias_method :last_week, :prev_week
-
-
# Short-hand for months_ago(1).
-
1
def prev_month
-
31
months_ago(1)
-
end
-
1
alias_method :last_month, :prev_month
-
-
# Short-hand for months_ago(3).
-
1
def prev_quarter
-
months_ago(3)
-
end
-
1
alias_method :last_quarter, :prev_quarter
-
-
# Short-hand for years_ago(1).
-
1
def prev_year
-
years_ago(1)
-
end
-
1
alias_method :last_year, :prev_year
-
-
# Returns the number of days to the start of the week on the given day.
-
# Week is assumed to start on +start_day+, default is
-
# +Date.beginning_of_week+ or +config.beginning_of_week+ when set.
-
1
def days_to_week_start(start_day = Date.beginning_of_week)
-
start_day_number = DAYS_INTO_WEEK[start_day]
-
current_day_number = wday != 0 ? wday - 1 : 6
-
(current_day_number - start_day_number) % 7
-
end
-
-
# Returns a new date/time representing the start of this week on the given day.
-
# Week is assumed to start on +start_day+, default is
-
# +Date.beginning_of_week+ or +config.beginning_of_week+ when set.
-
# +DateTime+ objects have their time set to 0:00.
-
1
def beginning_of_week(start_day = Date.beginning_of_week)
-
result = days_ago(days_to_week_start(start_day))
-
acts_like?(:time) ? result.midnight : result
-
end
-
1
alias :at_beginning_of_week :beginning_of_week
-
-
# Returns Monday of this week assuming that week starts on Monday.
-
# +DateTime+ objects have their time set to 0:00.
-
1
def monday
-
beginning_of_week(:monday)
-
end
-
-
# Returns a new date/time representing the end of this week on the given day.
-
# Week is assumed to start on +start_day+, default is
-
# +Date.beginning_of_week+ or +config.beginning_of_week+ when set.
-
# DateTime objects have their time set to 23:59:59.
-
1
def end_of_week(start_day = Date.beginning_of_week)
-
last_hour{ days_since(6 - days_to_week_start(start_day)) }
-
end
-
1
alias :at_end_of_week :end_of_week
-
-
# Returns Sunday of this week assuming that week starts on Monday.
-
# +DateTime+ objects have their time set to 23:59:59.
-
1
def sunday
-
end_of_week(:monday)
-
end
-
-
# Returns a new date/time representing the end of the month.
-
# DateTime objects will have a time set to 23:59:59.
-
1
def end_of_month
-
last_day = ::Time.days_in_month(month, year)
-
last_hour{ days_since(last_day - day) }
-
end
-
1
alias :at_end_of_month :end_of_month
-
-
# Returns a new date/time representing the end of the year.
-
# DateTime objects will have a time set to 23:59:59.
-
1
def end_of_year
-
change(:month => 12).end_of_month
-
end
-
1
alias :at_end_of_year :end_of_year
-
-
1
private
-
-
1
def first_hour
-
result = yield
-
acts_like?(:time) ? result.change(:hour => 0) : result
-
end
-
-
1
def last_hour
-
result = yield
-
acts_like?(:time) ? result.end_of_day : result
-
end
-
-
1
def days_span(day)
-
(DAYS_INTO_WEEK[day] - DAYS_INTO_WEEK[Date.beginning_of_week]) % 7
-
end
-
end
-
end
-
1
require 'active_support/core_ext/object/acts_like'
-
-
1
class DateTime
-
# Duck-types as a Date-like class. See Object#acts_like?.
-
1
def acts_like_date?
-
true
-
end
-
-
# Duck-types as a Time-like class. See Object#acts_like?.
-
1
def acts_like_time?
-
true
-
end
-
end
-
1
require 'active_support/deprecation'
-
-
1
class DateTime
-
1
class << self
-
# *DEPRECATED*: Use +DateTime.civil_from_format+ directly.
-
1
def local_offset
-
ActiveSupport::Deprecation.warn 'DateTime.local_offset is deprecated. Use DateTime.civil_from_format directly.'
-
-
::Time.local(2012).utc_offset.to_r / 86400
-
end
-
-
# Returns <tt>Time.zone.now.to_datetime</tt> when <tt>Time.zone</tt> or
-
# <tt>config.time_zone</tt> are set, otherwise returns
-
# <tt>Time.now.to_datetime</tt>.
-
1
def current
-
::Time.zone ? ::Time.zone.now.to_datetime : ::Time.now.to_datetime
-
end
-
end
-
-
# Tells whether the DateTime object's datetime lies in the past.
-
1
def past?
-
self < ::DateTime.current
-
end
-
-
# Tells whether the DateTime object's datetime lies in the future.
-
1
def future?
-
self > ::DateTime.current
-
end
-
-
# Seconds since midnight: DateTime.now.seconds_since_midnight.
-
1
def seconds_since_midnight
-
sec + (min * 60) + (hour * 3600)
-
end
-
-
# Returns a new DateTime where one or more of the elements have been changed
-
# according to the +options+ parameter. The time options (<tt>:hour</tt>,
-
# <tt>:minute</tt>, <tt>:sec</tt>) reset cascadingly, so if only the hour is
-
# passed, then minute and sec is set to 0. If the hour and minute is passed,
-
# then sec is set to 0. The +options+ parameter takes a hash with any of these
-
# keys: <tt>:year</tt>, <tt>:month</tt>, <tt>:day</tt>, <tt>:hour</tt>,
-
# <tt>:min</tt>, <tt>:sec</tt>, <tt>:offset</tt>, <tt>:start</tt>.
-
#
-
# DateTime.new(2012, 8, 29, 22, 35, 0).change(day: 1) # => DateTime.new(2012, 8, 1, 22, 35, 0)
-
# DateTime.new(2012, 8, 29, 22, 35, 0).change(year: 1981, day: 1) # => DateTime.new(1981, 8, 1, 22, 35, 0)
-
# DateTime.new(2012, 8, 29, 22, 35, 0).change(year: 1981, hour: 0) # => DateTime.new(1981, 8, 29, 0, 0, 0)
-
1
def change(options)
-
::DateTime.civil(
-
options.fetch(:year, year),
-
options.fetch(:month, month),
-
options.fetch(:day, day),
-
options.fetch(:hour, hour),
-
options.fetch(:min, options[:hour] ? 0 : min),
-
options.fetch(:sec, (options[:hour] || options[:min]) ? 0 : sec),
-
options.fetch(:offset, offset),
-
options.fetch(:start, start)
-
)
-
end
-
-
# Uses Date to provide precise Time calculations for years, months, and days.
-
# The +options+ parameter takes a hash with any of these keys: <tt>:years</tt>,
-
# <tt>:months</tt>, <tt>:weeks</tt>, <tt>:days</tt>, <tt>:hours</tt>,
-
# <tt>:minutes</tt>, <tt>:seconds</tt>.
-
1
def advance(options)
-
d = to_date.advance(options)
-
datetime_advanced_by_date = change(:year => d.year, :month => d.month, :day => d.day)
-
seconds_to_advance = \
-
options.fetch(:seconds, 0) +
-
options.fetch(:minutes, 0) * 60 +
-
options.fetch(:hours, 0) * 3600
-
-
if seconds_to_advance.zero?
-
datetime_advanced_by_date
-
else
-
datetime_advanced_by_date.since seconds_to_advance
-
end
-
end
-
-
# Returns a new DateTime representing the time a number of seconds ago.
-
# Do not use this method in combination with x.months, use months_ago instead!
-
1
def ago(seconds)
-
since(-seconds)
-
end
-
-
# Returns a new DateTime representing the time a number of seconds since the
-
# instance time. Do not use this method in combination with x.months, use
-
# months_since instead!
-
1
def since(seconds)
-
self + Rational(seconds.round, 86400)
-
end
-
1
alias :in :since
-
-
# Returns a new DateTime representing the start of the day (0:00).
-
1
def beginning_of_day
-
change(:hour => 0)
-
end
-
1
alias :midnight :beginning_of_day
-
1
alias :at_midnight :beginning_of_day
-
1
alias :at_beginning_of_day :beginning_of_day
-
-
# Returns a new DateTime representing the end of the day (23:59:59).
-
1
def end_of_day
-
change(:hour => 23, :min => 59, :sec => 59)
-
end
-
-
# Returns a new DateTime representing the start of the hour (hh:00:00).
-
1
def beginning_of_hour
-
change(:min => 0)
-
end
-
1
alias :at_beginning_of_hour :beginning_of_hour
-
-
# Returns a new DateTime representing the end of the hour (hh:59:59).
-
1
def end_of_hour
-
change(:min => 59, :sec => 59)
-
end
-
-
# Adjusts DateTime to UTC by adding its offset value; offset is set to 0.
-
#
-
# DateTime.civil(2005, 2, 21, 10, 11, 12, Rational(-6, 24)) # => Mon, 21 Feb 2005 10:11:12 -0600
-
# DateTime.civil(2005, 2, 21, 10, 11, 12, Rational(-6, 24)).utc # => Mon, 21 Feb 2005 16:11:12 +0000
-
1
def utc
-
3
new_offset(0)
-
end
-
1
alias_method :getutc, :utc
-
-
# Returns +true+ if <tt>offset == 0</tt>.
-
1
def utc?
-
1
offset == 0
-
end
-
-
# Returns the offset value in seconds.
-
1
def utc_offset
-
1
(offset * 86400).to_i
-
end
-
-
# Layers additional behavior on DateTime#<=> so that Time and
-
# ActiveSupport::TimeWithZone instances can be compared with a DateTime.
-
1
def <=>(other)
-
815
super other.to_datetime
-
end
-
-
end
-
1
require 'active_support/inflector/methods'
-
1
require 'active_support/core_ext/time/conversions'
-
1
require 'active_support/core_ext/date_time/calculations'
-
1
require 'active_support/values/time_zone'
-
-
1
class DateTime
-
# Convert to a formatted string. See Time::DATE_FORMATS for predefined formats.
-
#
-
# This method is aliased to <tt>to_s</tt>.
-
#
-
# === Examples
-
# datetime = DateTime.civil(2007, 12, 4, 0, 0, 0, 0) # => Tue, 04 Dec 2007 00:00:00 +0000
-
#
-
# datetime.to_formatted_s(:db) # => "2007-12-04 00:00:00"
-
# datetime.to_s(:db) # => "2007-12-04 00:00:00"
-
# datetime.to_s(:number) # => "20071204000000"
-
# datetime.to_formatted_s(:short) # => "04 Dec 00:00"
-
# datetime.to_formatted_s(:long) # => "December 04, 2007 00:00"
-
# datetime.to_formatted_s(:long_ordinal) # => "December 4th, 2007 00:00"
-
# datetime.to_formatted_s(:rfc822) # => "Tue, 04 Dec 2007 00:00:00 +0000"
-
#
-
# == Adding your own datetime formats to to_formatted_s
-
# DateTime formats are shared with Time. You can add your own to the
-
# Time::DATE_FORMATS hash. Use the format name as the hash key and
-
# either a strftime string or Proc instance that takes a time or
-
# datetime argument as the value.
-
#
-
# # config/initializers/time_formats.rb
-
# Time::DATE_FORMATS[:month_and_year] = '%B %Y'
-
# Time::DATE_FORMATS[:short_ordinal] = lambda { |time| time.strftime("%B #{time.day.ordinalize}") }
-
1
def to_formatted_s(format = :default)
-
6
if formatter = ::Time::DATE_FORMATS[format]
-
6
formatter.respond_to?(:call) ? formatter.call(self).to_s : strftime(formatter)
-
else
-
to_default_s
-
end
-
end
-
1
alias_method :to_default_s, :to_s if instance_methods(false).include?(:to_s)
-
1
alias_method :to_s, :to_formatted_s
-
-
#
-
# datetime = DateTime.civil(2000, 1, 1, 0, 0, 0, Rational(-6, 24))
-
# datetime.formatted_offset # => "-06:00"
-
# datetime.formatted_offset(false) # => "-0600"
-
1
def formatted_offset(colon = true, alternate_utc_string = nil)
-
1
utc? && alternate_utc_string || ActiveSupport::TimeZone.seconds_to_utc_offset(utc_offset, colon)
-
end
-
-
# Overrides the default inspect method with a human readable one, e.g., "Mon, 21 Feb 2005 14:30:00 +0000".
-
1
def readable_inspect
-
1
to_s(:rfc822)
-
end
-
1
alias_method :default_inspect, :inspect
-
1
alias_method :inspect, :readable_inspect
-
-
# Returns DateTime with local offset for given year if format is local else
-
# offset is zero.
-
#
-
# DateTime.civil_from_format :local, 2012
-
# # => Sun, 01 Jan 2012 00:00:00 +0300
-
# DateTime.civil_from_format :local, 2012, 12, 17
-
# # => Mon, 17 Dec 2012 00:00:00 +0000
-
1
def self.civil_from_format(utc_or_local, year, month=1, day=1, hour=0, min=0, sec=0)
-
1
if utc_or_local.to_sym == :local
-
1
offset = ::Time.local(year, month, day).utc_offset.to_r / 86400
-
else
-
offset = 0
-
end
-
1
civil(year, month, day, hour, min, sec, offset)
-
end
-
-
# Converts +self+ to a floating-point number of seconds since the Unix epoch.
-
1
def to_f
-
seconds_since_unix_epoch.to_f
-
end
-
-
# Converts +self+ to an integer number of seconds since the Unix epoch.
-
1
def to_i
-
seconds_since_unix_epoch.to_i
-
end
-
-
1
private
-
-
1
def offset_in_seconds
-
(offset * 86400).to_i
-
end
-
-
1
def seconds_since_unix_epoch
-
(jd - 2440588) * 86400 - offset_in_seconds + seconds_since_midnight
-
end
-
end
-
1
require 'active_support/core_ext/time/zones'
-
-
1
class DateTime
-
# Returns the simultaneous time in <tt>Time.zone</tt>.
-
#
-
# Time.zone = 'Hawaii' # => 'Hawaii'
-
# DateTime.new(2000).in_time_zone # => Fri, 31 Dec 1999 14:00:00 HST -10:00
-
#
-
# This method is similar to Time#localtime, except that it uses <tt>Time.zone</tt>
-
# as the local zone instead of the operating system's time zone.
-
#
-
# You can also pass in a TimeZone instance or string that identifies a TimeZone
-
# as an argument, and the conversion will be based on that zone instead of
-
# <tt>Time.zone</tt>.
-
#
-
# DateTime.new(2000).in_time_zone('Alaska') # => Fri, 31 Dec 1999 15:00:00 AKST -09:00
-
1
def in_time_zone(zone = ::Time.zone)
-
if zone
-
ActiveSupport::TimeWithZone.new(utc? ? self : getutc, ::Time.find_zone!(zone))
-
else
-
self
-
end
-
end
-
end
-
1
module Enumerable
-
# Calculates a sum from the elements.
-
#
-
# payments.sum { |p| p.price * p.tax_rate }
-
# payments.sum(&:price)
-
#
-
# The latter is a shortcut for:
-
#
-
# payments.inject(0) { |sum, p| sum + p.price }
-
#
-
# It can also calculate the sum without the use of a block.
-
#
-
# [5, 15, 10].sum # => 30
-
# ['foo', 'bar'].sum # => "foobar"
-
# [[1, 2], [3, 1, 5]].sum => [1, 2, 3, 1, 5]
-
#
-
# The default sum of an empty list is zero. You can override this default:
-
#
-
# [].sum(Payment.new(0)) { |i| i.amount } # => Payment.new(0)
-
1
def sum(identity = 0, &block)
-
6051
if block_given?
-
10
map(&block).sum(identity)
-
else
-
6109
inject { |sum, element| sum + element } || identity
-
end
-
end
-
-
# Convert an enumerable to a hash.
-
#
-
# people.index_by(&:login)
-
# => { "nextangle" => <Person ...>, "chade-" => <Person ...>, ...}
-
# people.index_by { |person| "#{person.first_name} #{person.last_name}" }
-
# => { "Chade- Fowlersburg-e" => <Person ...>, "David Heinemeier Hansson" => <Person ...>, ...}
-
1
def index_by
-
21
if block_given?
-
47
Hash[map { |elem| [yield(elem), elem] }]
-
else
-
to_enum :index_by
-
end
-
end
-
-
# Returns +true+ if the enumerable has more than 1 element. Functionally
-
# equivalent to <tt>enum.to_a.size > 1</tt>. Can be called with a block too,
-
# much like any?, so <tt>people.many? { |p| p.age > 26 }</tt> returns +true+
-
# if more than one person is over 26.
-
1
def many?
-
5
cnt = 0
-
5
if block_given?
-
4
any? do |element|
-
17
cnt += 1 if yield element
-
17
cnt > 1
-
end
-
else
-
2
any? { (cnt += 1) > 1 }
-
end
-
end
-
-
# The negative of the <tt>Enumerable#include?</tt>. Returns +true+ if the
-
# collection does not include the object.
-
1
def exclude?(object)
-
!include?(object)
-
end
-
end
-
-
1
class Range #:nodoc:
-
# Optimize range sum to use arithmetic progression if a block is not given and
-
# we have a range of numeric values.
-
1
def sum(identity = 0)
-
if block_given? || !(first.is_a?(Integer) && last.is_a?(Integer))
-
super
-
else
-
actual_last = exclude_end? ? (last - 1) : last
-
if actual_last >= first
-
(actual_last - first + 1) * (actual_last + first) / 2
-
else
-
identity
-
end
-
end
-
end
-
end
-
1
module ActiveSupport
-
1
FrozenObjectError = RuntimeError
-
end
-
1
require 'active_support/xml_mini'
-
1
require 'active_support/time'
-
1
require 'active_support/core_ext/object/blank'
-
1
require 'active_support/core_ext/object/to_param'
-
1
require 'active_support/core_ext/object/to_query'
-
1
require 'active_support/core_ext/array/wrap'
-
1
require 'active_support/core_ext/hash/reverse_merge'
-
1
require 'active_support/core_ext/string/inflections'
-
-
1
class Hash
-
# Returns a string containing an XML representation of its receiver:
-
#
-
# {'foo' => 1, 'bar' => 2}.to_xml
-
# # =>
-
# # <?xml version="1.0" encoding="UTF-8"?>
-
# # <hash>
-
# # <foo type="integer">1</foo>
-
# # <bar type="integer">2</bar>
-
# # </hash>
-
#
-
# To do so, the method loops over the pairs and builds nodes that depend on
-
# the _values_. Given a pair +key+, +value+:
-
#
-
# * If +value+ is a hash there's a recursive call with +key+ as <tt>:root</tt>.
-
#
-
# * If +value+ is an array there's a recursive call with +key+ as <tt>:root</tt>,
-
# and +key+ singularized as <tt>:children</tt>.
-
#
-
# * If +value+ is a callable object it must expect one or two arguments. Depending
-
# on the arity, the callable is invoked with the +options+ hash as first argument
-
# with +key+ as <tt>:root</tt>, and +key+ singularized as second argument. The
-
# callable can add nodes by using <tt>options[:builder]</tt>.
-
#
-
# 'foo'.to_xml(lambda { |options, key| options[:builder].b(key) })
-
# # => "<b>foo</b>"
-
#
-
# * If +value+ responds to +to_xml+ the method is invoked with +key+ as <tt>:root</tt>.
-
#
-
# class Foo
-
# def to_xml(options)
-
# options[:builder].bar 'fooing!'
-
# end
-
# end
-
#
-
# { foo: Foo.new }.to_xml(skip_instruct: true)
-
# # => "<hash><bar>fooing!</bar></hash>"
-
#
-
# * Otherwise, a node with +key+ as tag is created with a string representation of
-
# +value+ as text node. If +value+ is +nil+ an attribute "nil" set to "true" is added.
-
# Unless the option <tt>:skip_types</tt> exists and is true, an attribute "type" is
-
# added as well according to the following mapping:
-
#
-
# XML_TYPE_NAMES = {
-
# "Symbol" => "symbol",
-
# "Fixnum" => "integer",
-
# "Bignum" => "integer",
-
# "BigDecimal" => "decimal",
-
# "Float" => "float",
-
# "TrueClass" => "boolean",
-
# "FalseClass" => "boolean",
-
# "Date" => "date",
-
# "DateTime" => "dateTime",
-
# "Time" => "dateTime"
-
# }
-
#
-
# By default the root node is "hash", but that's configurable via the <tt>:root</tt> option.
-
#
-
# The default XML builder is a fresh instance of <tt>Builder::XmlMarkup</tt>. You can
-
# configure your own builder with the <tt>:builder</tt> option. The method also accepts
-
# options like <tt>:dasherize</tt> and friends, they are forwarded to the builder.
-
1
def to_xml(options = {})
-
10
require 'active_support/builder' unless defined?(Builder)
-
-
10
options = options.dup
-
10
options[:indent] ||= 2
-
10
options[:root] ||= 'hash'
-
10
options[:builder] ||= Builder::XmlMarkup.new(indent: options[:indent])
-
-
10
builder = options[:builder]
-
10
builder.instruct! unless options.delete(:skip_instruct)
-
-
10
root = ActiveSupport::XmlMini.rename_key(options[:root].to_s, options)
-
-
10
builder.tag!(root) do
-
20
each { |key, value| ActiveSupport::XmlMini.to_tag(key, value, options) }
-
10
yield builder if block_given?
-
end
-
end
-
-
1
class << self
-
1
def from_xml(xml)
-
8
typecast_xml_value(unrename_keys(ActiveSupport::XmlMini.parse(xml)))
-
end
-
-
1
private
-
1
def typecast_xml_value(value)
-
202
case value
-
when Hash
-
192
if value['type'] == 'array'
-
14
_, entries = Array.wrap(value.detect { |k,v| not v.is_a?(String) })
-
5
if entries.nil? || (c = value['__content__'] && c.blank?)
-
1
[]
-
else
-
4
case entries # something weird with classes not matching here. maybe singleton methods breaking is_a?
-
when Array
-
19
entries.collect { |v| typecast_xml_value(v) }
-
when Hash
-
[typecast_xml_value(entries)]
-
else
-
raise "can't typecast #{entries.inspect}"
-
end
-
end
-
elsif value['type'] == 'file' ||
-
187
(value['__content__'] && (value.keys.size == 1 || value['__content__'].present?))
-
145
content = value['__content__']
-
145
if parser = ActiveSupport::XmlMini::PARSING[value['type']]
-
106
parser.arity == 1 ? parser.call(content) : parser.call(content, value)
-
else
-
39
content
-
end
-
42
elsif value['type'] == 'string' && value['nil'] != 'true'
-
''
-
# blank or nil parsed values are represented by nil
-
42
elsif value.blank? || value['nil'] == 'true'
-
nil
-
# If the type is the only element which makes it then
-
# this still makes the value nil, except if type is
-
# a XML node(where type['value'] is a Hash)
-
29
elsif value['type'] && value.size == 1 && !value['type'].is_a?(::Hash)
-
nil
-
else
-
208
xml_value = Hash[value.map { |k,v| [k, typecast_xml_value(v)] }]
-
-
# Turn { files: { file: #<StringIO> } } into { files: #<StringIO> } so it is compatible with
-
# how multipart uploaded files from HTML appear
-
29
xml_value['file'].is_a?(StringIO) ? xml_value['file'] : xml_value
-
end
-
when Array
-
value.map! { |i| typecast_xml_value(i) }
-
value.length > 1 ? value : value.first
-
when String
-
10
value
-
else
-
raise "can't typecast #{value.class.name} - #{value.inspect}"
-
end
-
end
-
-
1
def unrename_keys(params)
-
491
case params
-
when Hash
-
660
Hash[params.map { |k,v| [k.to_s.tr('-', '_'), unrename_keys(v)] } ]
-
when Array
-
19
params.map { |v| unrename_keys(v) }
-
else
-
295
params
-
end
-
end
-
end
-
end
-
1
class Hash
-
# Returns a new hash with +self+ and +other_hash+ merged recursively.
-
#
-
# h1 = { x: { y: [4,5,6] }, z: [7,8,9] }
-
# h2 = { x: { y: [7,8,9] }, z: 'xyz' }
-
#
-
# h1.deep_merge(h2) #=> {x: {y: [7, 8, 9]}, z: "xyz"}
-
# h2.deep_merge(h1) #=> {x: {y: [4, 5, 6]}, z: [7, 8, 9]}
-
# h1.deep_merge(h2) { |key, old, new| Array.wrap(old) + Array.wrap(new) }
-
# #=> {:x=>{:y=>[4, 5, 6, 7, 8, 9]}, :z=>[7, 8, 9, "xyz"]}
-
1
def deep_merge(other_hash, &block)
-
64
dup.deep_merge!(other_hash, &block)
-
end
-
-
# Same as +deep_merge+, but modifies +self+.
-
1
def deep_merge!(other_hash, &block)
-
150
other_hash.each_pair do |k,v|
-
228
tv = self[k]
-
228
if tv.is_a?(Hash) && v.is_a?(Hash)
-
59
self[k] = tv.deep_merge(v, &block)
-
else
-
169
self[k] = block && tv ? block.call(k, tv, v) : v
-
end
-
end
-
150
self
-
end
-
end
-
1
class Hash
-
# Return a hash that includes everything but the given keys. This is useful for
-
# limiting a set of parameters to everything but a few known toggles:
-
#
-
# @person.update_attributes(params[:person].except(:admin))
-
1
def except(*keys)
-
7064
dup.except!(*keys)
-
end
-
-
# Replaces the hash without the given keys.
-
1
def except!(*keys)
-
47410
keys.each { |key| delete(key) }
-
7091
self
-
end
-
end
-
1
require 'active_support/hash_with_indifferent_access'
-
-
1
class Hash
-
-
# Returns an <tt>ActiveSupport::HashWithIndifferentAccess</tt> out of its receiver:
-
#
-
# { a: 1 }.with_indifferent_access['a'] # => 1
-
1
def with_indifferent_access
-
292
ActiveSupport::HashWithIndifferentAccess.new_from_hash_copying_default(self)
-
end
-
-
# Called when object is nested under an object that receives
-
# #with_indifferent_access. This method will be called on the current object
-
# by the enclosing object and is aliased to #with_indifferent_access by
-
# default. Subclasses of Hash may overwrite this method to return +self+ if
-
# converting to an <tt>ActiveSupport::HashWithIndifferentAccess</tt> would not be
-
# desirable.
-
#
-
# b = { b: 1 }
-
# { a: b }.with_indifferent_access['a'] # calls b.nested_under_indifferent_access
-
1
alias nested_under_indifferent_access with_indifferent_access
-
end
-
1
class Hash
-
# Return a new hash with all keys converted using the block operation.
-
#
-
# hash = { name: 'Rob', age: '28' }
-
#
-
# hash.transform_keys{ |key| key.to_s.upcase }
-
# # => { "NAME" => "Rob", "AGE" => "28" }
-
1
def transform_keys
-
4278
result = {}
-
4278
each_key do |key|
-
4971
result[yield(key)] = self[key]
-
end
-
4278
result
-
end
-
-
# Destructively convert all keys using the block operations.
-
# Same as transform_keys but modifies +self+.
-
1
def transform_keys!
-
2
keys.each do |key|
-
4
self[yield(key)] = delete(key)
-
end
-
2
self
-
end
-
-
# Return a new hash with all keys converted to strings.
-
#
-
# hash = { name: 'Rob', age: '28' }
-
#
-
# hash.stringify_keys
-
# #=> { "name" => "Rob", "age" => "28" }
-
1
def stringify_keys
-
8630
transform_keys{ |key| key.to_s }
-
end
-
-
# Destructively convert all keys to strings. Same as
-
# +stringify_keys+, but modifies +self+.
-
1
def stringify_keys!
-
6
transform_keys!{ |key| key.to_s }
-
end
-
-
# Return a new hash with all keys converted to symbols, as long as
-
# they respond to +to_sym+.
-
#
-
# hash = { 'name' => 'Rob', 'age' => '28' }
-
#
-
# hash.symbolize_keys
-
# #=> { name: "Rob", age: "28" }
-
1
def symbolize_keys
-
619
transform_keys{ |key| key.to_sym rescue key }
-
end
-
1
alias_method :to_options, :symbolize_keys
-
-
# Destructively convert all keys to symbols, as long as they respond
-
# to +to_sym+. Same as +symbolize_keys+, but modifies +self+.
-
1
def symbolize_keys!
-
transform_keys!{ |key| key.to_sym rescue key }
-
end
-
1
alias_method :to_options!, :symbolize_keys!
-
-
# Validate all keys in a hash match <tt>*valid_keys</tt>, raising ArgumentError
-
# on a mismatch. Note that keys are NOT treated indifferently, meaning if you
-
# use strings for keys but assert symbols as keys, this will fail.
-
#
-
# { name: 'Rob', years: '28' }.assert_valid_keys(:name, :age) # => raises "ArgumentError: Unknown key: years"
-
# { name: 'Rob', age: '28' }.assert_valid_keys('name', 'age') # => raises "ArgumentError: Unknown key: name"
-
# { name: 'Rob', age: '28' }.assert_valid_keys(:name, :age) # => passes, raises nothing
-
1
def assert_valid_keys(*valid_keys)
-
5887
valid_keys.flatten!
-
5887
each_key do |k|
-
2128
raise ArgumentError.new("Unknown key: #{k}") unless valid_keys.include?(k)
-
end
-
end
-
-
# Return a new hash with all keys converted by the block operation.
-
# This includes the keys from the root hash and from all
-
# nested hashes.
-
#
-
# hash = { person: { name: 'Rob', age: '28' } }
-
#
-
# hash.deep_transform_keys{ |key| key.to_s.upcase }
-
# # => { "PERSON" => { "NAME" => "Rob", "AGE" => "28" } }
-
1
def deep_transform_keys(&block)
-
717
result = {}
-
717
each do |key, value|
-
2066
result[yield(key)] = value.is_a?(Hash) ? value.deep_transform_keys(&block) : value
-
end
-
717
result
-
end
-
-
# Destructively convert all keys by using the block operation.
-
# This includes the keys from the root hash and from all
-
# nested hashes.
-
1
def deep_transform_keys!(&block)
-
keys.each do |key|
-
value = delete(key)
-
self[yield(key)] = value.is_a?(Hash) ? value.deep_transform_keys!(&block) : value
-
end
-
self
-
end
-
-
# Return a new hash with all keys converted to strings.
-
# This includes the keys from the root hash and from all
-
# nested hashes.
-
#
-
# hash = { person: { name: 'Rob', age: '28' } }
-
#
-
# hash.deep_stringify_keys
-
# # => { "person" => { "name" => "Rob", "age" => "28" } }
-
1
def deep_stringify_keys
-
deep_transform_keys{ |key| key.to_s }
-
end
-
-
# Destructively convert all keys to strings.
-
# This includes the keys from the root hash and from all
-
# nested hashes.
-
1
def deep_stringify_keys!
-
deep_transform_keys!{ |key| key.to_s }
-
end
-
-
# Return a new hash with all keys converted to symbols, as long as
-
# they respond to +to_sym+. This includes the keys from the root hash
-
# and from all nested hashes.
-
#
-
# hash = { 'person' => { 'name' => 'Rob', 'age' => '28' } }
-
#
-
# hash.deep_symbolize_keys
-
# # => { person: { name: "Rob", age: "28" } }
-
1
def deep_symbolize_keys
-
2152
deep_transform_keys{ |key| key.to_sym rescue key }
-
end
-
-
# Destructively convert all keys to symbols, as long as they respond
-
# to +to_sym+. This includes the keys from the root hash and from all
-
# nested hashes.
-
1
def deep_symbolize_keys!
-
deep_transform_keys!{ |key| key.to_sym rescue key }
-
end
-
end
-
1
class Hash
-
# Merges the caller into +other_hash+. For example,
-
#
-
# options = options.reverse_merge(size: 25, velocity: 10)
-
#
-
# is equivalent to
-
#
-
# options = { size: 25, velocity: 10 }.merge(options)
-
#
-
# This is particularly useful for initializing an options hash
-
# with default values.
-
1
def reverse_merge(other_hash)
-
30
other_hash.merge(self)
-
end
-
-
# Destructive +reverse_merge+.
-
1
def reverse_merge!(other_hash)
-
# right wins if there is no left
-
10
merge!( other_hash ){|key,left,right| left }
-
end
-
1
alias_method :reverse_update, :reverse_merge!
-
end
-
1
class Hash
-
# Slice a hash to include only the given keys. This is useful for
-
# limiting an options hash to valid keys before passing to a method:
-
#
-
# def search(criteria = {})
-
# criteria.assert_valid_keys(:mass, :velocity, :time)
-
# end
-
#
-
# search(options.slice(:mass, :velocity, :time))
-
#
-
# If you have an array of keys you want to limit to, you should splat them:
-
#
-
# valid_keys = [:mass, :velocity, :time]
-
# search(options.slice(*valid_keys))
-
1
def slice(*keys)
-
473
keys.map! { |key| convert_key(key) } if respond_to?(:convert_key, true)
-
4692
keys.each_with_object(self.class.new) { |k, hash| hash[k] = self[k] if has_key?(k) }
-
end
-
-
# Replaces the hash with only the given keys.
-
# Returns a hash containing the removed key/value pairs.
-
#
-
# { a: 1, b: 2, c: 3, d: 4 }.slice!(:a, :b)
-
# # => {:c=>3, :d=>4}
-
1
def slice!(*keys)
-
2
keys.map! { |key| convert_key(key) } if respond_to?(:convert_key, true)
-
2
omit = slice(*self.keys - keys)
-
2
hash = slice(*keys)
-
2
replace(hash)
-
2
omit
-
end
-
-
# Removes and returns the key/value pairs matching the given keys.
-
#
-
# { a: 1, b: 2, c: 3, d: 4 }.extract!(:a, :b) # => {:a=>1, :b=>2}
-
# { a: 1, b: 2 }.extract!(:a, :x) # => {:a=>1}
-
1
def extract!(*keys)
-
keys.each_with_object(self.class.new) { |key, result| result[key] = delete(key) if has_key?(key) }
-
end
-
end
-
1
class Integer
-
# Enables the use of time calculations and declarations, like <tt>45.minutes +
-
# 2.hours + 4.years</tt>.
-
#
-
# These methods use Time#advance for precise date calculations when using
-
# <tt>from_now</tt>, +ago+, etc. as well as adding or subtracting their
-
# results from a Time object.
-
#
-
# # equivalent to Time.now.advance(months: 1)
-
# 1.month.from_now
-
#
-
# # equivalent to Time.now.advance(years: 2)
-
# 2.years.from_now
-
#
-
# # equivalent to Time.now.advance(months: 4, years: 5)
-
# (4.months + 5.years).from_now
-
#
-
# While these methods provide precise calculation when used as in the examples
-
# above, care should be taken to note that this is not true if the result of
-
# +months+, +years+, etc is converted before use:
-
#
-
# # equivalent to 30.days.to_i.from_now
-
# 1.month.to_i.from_now
-
#
-
# # equivalent to 365.25.days.to_f.from_now
-
# 1.year.to_f.from_now
-
#
-
# In such cases, Ruby's core
-
# Date[http://ruby-doc.org/stdlib/libdoc/date/rdoc/Date.html] and
-
# Time[http://ruby-doc.org/stdlib/libdoc/time/rdoc/Time.html] should be used for precision
-
# date and time arithmetic.
-
1
def months
-
ActiveSupport::Duration.new(self * 30.days, [[:months, self]])
-
end
-
1
alias :month :months
-
-
1
def years
-
1
ActiveSupport::Duration.new(self * 365.25.days, [[:years, self]])
-
end
-
1
alias :year :years
-
end
-
1
module Kernel
-
# class_eval on an object acts like singleton_class.class_eval.
-
1
def class_eval(*args, &block)
-
6
singleton_class.class_eval(*args, &block)
-
end
-
end
-
1
class LoadError
-
1
REGEXPS = [
-
/^no such file to load -- (.+)$/i,
-
/^Missing \w+ (?:file\s*)?([^\s]+.rb)$/i,
-
/^Missing API definition file in (.+)$/i,
-
/^cannot load such file -- (.+)$/i,
-
]
-
-
1
unless method_defined?(:path)
-
1
def path
-
@path ||= begin
-
REGEXPS.find do |regex|
-
message =~ regex
-
end
-
$1
-
end
-
end
-
end
-
-
1
def is_missing?(location)
-
location.sub(/\.rb$/, '') == path.sub(/\.rb$/, '')
-
end
-
end
-
-
1
MissingSourceFile = LoadError
-
1
class Module
-
# Encapsulates the common pattern of:
-
#
-
# alias_method :foo_without_feature, :foo
-
# alias_method :foo, :foo_with_feature
-
#
-
# With this, you simply do:
-
#
-
# alias_method_chain :foo, :feature
-
#
-
# And both aliases are set up for you.
-
#
-
# Query and bang methods (foo?, foo!) keep the same punctuation:
-
#
-
# alias_method_chain :foo?, :feature
-
#
-
# is equivalent to
-
#
-
# alias_method :foo_without_feature?, :foo?
-
# alias_method :foo?, :foo_with_feature?
-
#
-
# so you can safely chain foo, foo?, and foo! with the same feature.
-
1
def alias_method_chain(target, feature)
-
# Strip out punctuation on predicates or bang methods since
-
# e.g. target?_without_feature is not a valid method name.
-
16
aliased_target, punctuation = target.to_s.sub(/([?!=])$/, ''), $1
-
16
yield(aliased_target, punctuation) if block_given?
-
-
16
with_method = "#{aliased_target}_with_#{feature}#{punctuation}"
-
16
without_method = "#{aliased_target}_without_#{feature}#{punctuation}"
-
-
16
alias_method without_method, target
-
16
alias_method target, with_method
-
-
case
-
when public_method_defined?(without_method)
-
15
public target
-
when protected_method_defined?(without_method)
-
protected target
-
when private_method_defined?(without_method)
-
1
private target
-
16
end
-
end
-
-
# Allows you to make aliases for attributes, which includes
-
# getter, setter, and query methods.
-
#
-
# class Content < ActiveRecord::Base
-
# # has a title attribute
-
# end
-
#
-
# class Email < Content
-
# alias_attribute :subject, :title
-
# end
-
#
-
# e = Email.find(1)
-
# e.title # => "Superstars"
-
# e.subject # => "Superstars"
-
# e.subject? # => true
-
# e.subject = "Megastars"
-
# e.title # => "Megastars"
-
1
def alias_attribute(new_name, old_name)
-
module_eval <<-STR, __FILE__, __LINE__ + 1
-
def #{new_name}; self.#{old_name}; end # def subject; self.title; end
-
def #{new_name}?; self.#{old_name}?; end # def subject?; self.title?; end
-
def #{new_name}=(v); self.#{old_name} = v; end # def subject=(v); self.title = v; end
-
STR
-
end
-
end
-
1
class Module
-
# A module may or may not have a name.
-
#
-
# module M; end
-
# M.name # => "M"
-
#
-
# m = Module.new
-
# m.name # => nil
-
#
-
# A module gets a name when it is first assigned to a constant. Either
-
# via the +module+ or +class+ keyword or by an explicit assignment:
-
#
-
# m = Module.new # creates an anonymous module
-
# M = m # => m gets a name here as a side-effect
-
# m.name # => "M"
-
1
def anonymous?
-
573
name.nil?
-
end
-
end
-
1
require 'active_support/core_ext/array/extract_options'
-
-
1
class Module
-
1
def mattr_reader(*syms)
-
23
options = syms.extract_options!
-
23
syms.each do |sym|
-
23
raise NameError.new('invalid attribute name') unless sym =~ /^[_A-Za-z]\w*$/
-
23
class_eval(<<-EOS, __FILE__, __LINE__ + 1)
-
@@#{sym} = nil unless defined? @@#{sym}
-
-
def self.#{sym}
-
@@#{sym}
-
end
-
EOS
-
-
23
unless options[:instance_reader] == false || options[:instance_accessor] == false
-
22
class_eval(<<-EOS, __FILE__, __LINE__ + 1)
-
def #{sym}
-
@@#{sym}
-
end
-
EOS
-
end
-
end
-
end
-
-
1
def mattr_writer(*syms)
-
23
options = syms.extract_options!
-
23
syms.each do |sym|
-
23
raise NameError.new('invalid attribute name') unless sym =~ /^[_A-Za-z]\w*$/
-
23
class_eval(<<-EOS, __FILE__, __LINE__ + 1)
-
def self.#{sym}=(obj)
-
@@#{sym} = obj
-
end
-
EOS
-
-
23
unless options[:instance_writer] == false || options[:instance_accessor] == false
-
13
class_eval(<<-EOS, __FILE__, __LINE__ + 1)
-
def #{sym}=(obj)
-
@@#{sym} = obj
-
end
-
EOS
-
end
-
end
-
end
-
-
# Extends the module object with module and instance accessors for class attributes,
-
# just like the native attr* accessors for instance attributes.
-
#
-
# module AppConfiguration
-
# mattr_accessor :google_api_key
-
#
-
# self.google_api_key = "123456789"
-
# end
-
#
-
# AppConfiguration.google_api_key # => "123456789"
-
# AppConfiguration.google_api_key = "overriding the api key!"
-
# AppConfiguration.google_api_key # => "overriding the api key!"
-
#
-
# To opt out of the instance writer method, pass <tt>instance_writer: false</tt>.
-
# To opt out of the instance reader method, pass <tt>instance_reader: false</tt>.
-
# To opt out of both instance methods, pass <tt>instance_accessor: false</tt>.
-
1
def mattr_accessor(*syms)
-
23
mattr_reader(*syms)
-
23
mattr_writer(*syms)
-
end
-
end
-
1
class Module
-
# Provides a delegate class method to easily expose contained objects' public methods
-
# as your own. Pass one or more methods (specified as symbols or strings)
-
# and the name of the target object via the <tt>:to</tt> option (also a symbol
-
# or string). At least one method and the <tt>:to</tt> option are required.
-
#
-
# Delegation is particularly useful with Active Record associations:
-
#
-
# class Greeter < ActiveRecord::Base
-
# def hello
-
# 'hello'
-
# end
-
#
-
# def goodbye
-
# 'goodbye'
-
# end
-
# end
-
#
-
# class Foo < ActiveRecord::Base
-
# belongs_to :greeter
-
# delegate :hello, to: :greeter
-
# end
-
#
-
# Foo.new.hello # => "hello"
-
# Foo.new.goodbye # => NoMethodError: undefined method `goodbye' for #<Foo:0x1af30c>
-
#
-
# Multiple delegates to the same target are allowed:
-
#
-
# class Foo < ActiveRecord::Base
-
# belongs_to :greeter
-
# delegate :hello, :goodbye, to: :greeter
-
# end
-
#
-
# Foo.new.goodbye # => "goodbye"
-
#
-
# Methods can be delegated to instance variables, class variables, or constants
-
# by providing them as a symbols:
-
#
-
# class Foo
-
# CONSTANT_ARRAY = [0,1,2,3]
-
# @@class_array = [4,5,6,7]
-
#
-
# def initialize
-
# @instance_array = [8,9,10,11]
-
# end
-
# delegate :sum, to: :CONSTANT_ARRAY
-
# delegate :min, to: :@@class_array
-
# delegate :max, to: :@instance_array
-
# end
-
#
-
# Foo.new.sum # => 6
-
# Foo.new.min # => 4
-
# Foo.new.max # => 11
-
#
-
# It's also possible to delegate a method to the class by using +:class+:
-
#
-
# class Foo
-
# def self.hello
-
# "world"
-
# end
-
#
-
# delegate :hello, to: :class
-
# end
-
#
-
# Foo.new.hello # => "world"
-
#
-
# Delegates can optionally be prefixed using the <tt>:prefix</tt> option. If the value
-
# is <tt>true</tt>, the delegate methods are prefixed with the name of the object being
-
# delegated to.
-
#
-
# Person = Struct.new(:name, :address)
-
#
-
# class Invoice < Struct.new(:client)
-
# delegate :name, :address, to: :client, prefix: true
-
# end
-
#
-
# john_doe = Person.new('John Doe', 'Vimmersvej 13')
-
# invoice = Invoice.new(john_doe)
-
# invoice.client_name # => "John Doe"
-
# invoice.client_address # => "Vimmersvej 13"
-
#
-
# It is also possible to supply a custom prefix.
-
#
-
# class Invoice < Struct.new(:client)
-
# delegate :name, :address, to: :client, prefix: :customer
-
# end
-
#
-
# invoice = Invoice.new(john_doe)
-
# invoice.customer_name # => 'John Doe'
-
# invoice.customer_address # => 'Vimmersvej 13'
-
#
-
# If the delegate object is +nil+ an exception is raised, and that happens
-
# no matter whether +nil+ responds to the delegated method. You can get a
-
# +nil+ instead with the +:allow_nil+ option.
-
#
-
# class Foo
-
# attr_accessor :bar
-
# def initialize(bar = nil)
-
# @bar = bar
-
# end
-
# delegate :zoo, to: :bar
-
# end
-
#
-
# Foo.new.zoo # raises NoMethodError exception (you called nil.zoo)
-
#
-
# class Foo
-
# attr_accessor :bar
-
# def initialize(bar = nil)
-
# @bar = bar
-
# end
-
# delegate :zoo, to: :bar, allow_nil: true
-
# end
-
#
-
# Foo.new.zoo # returns nil
-
1
def delegate(*methods)
-
61
options = methods.pop
-
61
unless options.is_a?(Hash) && to = options[:to]
-
raise ArgumentError, 'Delegation needs a target. Supply an options hash with a :to key as the last argument (e.g. delegate :hello, to: :greeter).'
-
end
-
-
61
prefix, allow_nil = options.values_at(:prefix, :allow_nil)
-
-
61
if prefix == true && to =~ /^[^a-z_]/
-
raise ArgumentError, 'Can only automatically set the delegation prefix when delegating to a method.'
-
end
-
-
61
method_prefix = \
-
if prefix
-
1
"#{prefix == true ? to : prefix}_"
-
else
-
60
''
-
end
-
-
61
file, line = caller.first.split(':', 2)
-
61
line = line.to_i
-
-
61
to = to.to_s
-
61
to = 'self.class' if to == 'class'
-
-
61
methods.each do |method|
-
# Attribute writer methods only accept one argument. Makes sure []=
-
# methods still accept two arguments.
-
182
definition = (method =~ /[^\]]=$/) ? 'arg' : '*args, &block'
-
-
182
if allow_nil
-
module_eval(<<-EOS, file, line - 2)
-
def #{method_prefix}#{method}(#{definition}) # def customer_name(*args, &block)
-
if #{to} || #{to}.respond_to?(:#{method}) # if client || client.respond_to?(:name)
-
#{to}.#{method}(#{definition}) # client.name(*args, &block)
-
end # end
-
end # end
-
EOS
-
else
-
182
exception = %(raise "#{self}##{method_prefix}#{method} delegated to #{to}.#{method}, but #{to} is nil: \#{self.inspect}")
-
-
182
module_eval(<<-EOS, file, line - 1)
-
def #{method_prefix}#{method}(#{definition}) # def customer_name(*args, &block)
-
#{to}.#{method}(#{definition}) # client.name(*args, &block)
-
rescue NoMethodError # rescue NoMethodError
-
if #{to}.nil? # if client.nil?
-
#{exception} # # add helpful message to the exception
-
else # else
-
raise # raise
-
end # end
-
end # end
-
EOS
-
end
-
end
-
end
-
end
-
1
require 'active_support/deprecation/method_wrappers'
-
-
1
class Module
-
# deprecate :foo
-
# deprecate bar: 'message'
-
# deprecate :foo, :bar, baz: 'warning!', qux: 'gone!'
-
#
-
# You can also use custom deprecator instance:
-
#
-
# deprecate :foo, deprecator: MyLib::Deprecator.new
-
# deprecate :foo, bar: "warning!", deprecator: MyLib::Deprecator.new
-
#
-
# \Custom deprecators must respond to <tt>deprecation_warning(deprecated_method_name, message, caller_backtrace)</tt>
-
# method where you can implement your custom warning behavior.
-
#
-
# class MyLib::Deprecator
-
# def deprecation_warning(deprecated_method_name, message, caller_backtrace)
-
# message = "#{method_name} is deprecated and will be removed from MyLibrary | #{message}"
-
# Kernel.warn message
-
# end
-
# end
-
1
def deprecate(*method_names)
-
1
ActiveSupport::Deprecation.deprecate_methods(self, *method_names)
-
end
-
end
-
1
require 'active_support/inflector'
-
-
1
class Module
-
# Returns the name of the module containing this one.
-
#
-
# M::N.parent_name # => "M"
-
1
def parent_name
-
2080
if defined? @parent_name
-
1847
@parent_name
-
else
-
233
@parent_name = name =~ /::[^:]+\Z/ ? $`.freeze : nil
-
end
-
end
-
-
# Returns the module which contains this one according to its name.
-
#
-
# module M
-
# module N
-
# end
-
# end
-
# X = M::N
-
#
-
# M::N.parent # => M
-
# X.parent # => M
-
#
-
# The parent of top-level and anonymous modules is Object.
-
#
-
# M.parent # => Object
-
# Module.new.parent # => Object
-
1
def parent
-
918
parent_name ? ActiveSupport::Inflector.constantize(parent_name) : Object
-
end
-
-
# Returns all the parents of this module according to its name, ordered from
-
# nested outwards. The receiver is not contained within the result.
-
#
-
# module M
-
# module N
-
# end
-
# end
-
# X = M::N
-
#
-
# M.parents # => [Object]
-
# M::N.parents # => [M, Object]
-
# X.parents # => [M, Object]
-
1
def parents
-
834
parents = []
-
834
if parent_name
-
141
parts = parent_name.split('::')
-
141
until parts.empty?
-
298
parents << ActiveSupport::Inflector.constantize(parts * '::')
-
298
parts.pop
-
end
-
end
-
834
parents << Object unless parents.include? Object
-
834
parents
-
end
-
-
1
def local_constants #:nodoc:
-
500
constants(false)
-
end
-
-
# *DEPRECATED*: Use +local_constants+ instead.
-
#
-
# Returns the names of the constants defined locally as strings.
-
#
-
# module M
-
# X = 1
-
# end
-
# M.local_constant_names # => ["X"]
-
#
-
# This method is useful for forward compatibility, since Ruby 1.8 returns
-
# constant names as strings, whereas 1.9 returns them as symbols.
-
1
def local_constant_names
-
ActiveSupport::Deprecation.warn 'Module#local_constant_names is deprecated, use Module#local_constants instead'
-
local_constants.map { |c| c.to_s }
-
end
-
end
-
1
require 'active_support/core_ext/string/inflections'
-
-
#--
-
# Allows code reuse in the methods below without polluting Module.
-
#++
-
1
module QualifiedConstUtils
-
1
def self.raise_if_absolute(path)
-
1075
raise NameError.new("wrong constant name #$&") if path =~ /\A::[^:]+/
-
end
-
-
1
def self.names(path)
-
1075
path.split('::')
-
end
-
end
-
-
##
-
# Extends the API for constants to be able to deal with qualified names. Arguments
-
# are assumed to be relative to the receiver.
-
#
-
#--
-
# Qualified names are required to be relative because we are extending existing
-
# methods that expect constant names, ie, relative paths of length 1. For example,
-
# Object.const_get('::String') raises NameError and so does qualified_const_get.
-
#++
-
1
class Module
-
1
def qualified_const_defined?(path, search_parents=true)
-
1075
QualifiedConstUtils.raise_if_absolute(path)
-
-
1075
QualifiedConstUtils.names(path).inject(self) do |mod, name|
-
1150
return unless mod.const_defined?(name, search_parents)
-
1149
mod.const_get(name)
-
end
-
1074
return true
-
end
-
-
1
def qualified_const_get(path)
-
QualifiedConstUtils.raise_if_absolute(path)
-
-
QualifiedConstUtils.names(path).inject(self) do |mod, name|
-
mod.const_get(name)
-
end
-
end
-
-
1
def qualified_const_set(path, value)
-
QualifiedConstUtils.raise_if_absolute(path)
-
-
const_name = path.demodulize
-
mod_name = path.deconstantize
-
mod = mod_name.empty? ? self : qualified_const_get(mod_name)
-
mod.const_set(const_name, value)
-
end
-
end
-
1
class Module
-
1
def remove_possible_method(method)
-
10434
if method_defined?(method) || private_method_defined?(method)
-
8887
undef_method(method)
-
end
-
end
-
-
1
def redefine_method(method, &block)
-
11
remove_possible_method(method)
-
11
define_method(method, &block)
-
end
-
end
-
1
class NameError
-
# Extract the name of the missing constant from the exception message.
-
1
def missing_name
-
4
if /undefined local variable or method/ !~ message
-
4
$1 if /((::)?([A-Z]\w*)(::[A-Z]\w*)*)$/ =~ message
-
end
-
end
-
-
# Was this exception raised because the given name was missing?
-
1
def missing_name?(name)
-
4
if name.is_a? Symbol
-
last_name = (missing_name || '').split('::').last
-
last_name == name.to_s
-
else
-
4
missing_name == name.to_s
-
end
-
end
-
end
-
1
require 'active_support/duration'
-
1
require 'active_support/core_ext/time/calculations'
-
1
require 'active_support/core_ext/time/acts_like'
-
-
1
class Numeric
-
# Enables the use of time calculations and declarations, like 45.minutes + 2.hours + 4.years.
-
#
-
# These methods use Time#advance for precise date calculations when using from_now, ago, etc.
-
# as well as adding or subtracting their results from a Time object. For example:
-
#
-
# # equivalent to Time.current.advance(months: 1)
-
# 1.month.from_now
-
#
-
# # equivalent to Time.current.advance(years: 2)
-
# 2.years.from_now
-
#
-
# # equivalent to Time.current.advance(months: 4, years: 5)
-
# (4.months + 5.years).from_now
-
#
-
# While these methods provide precise calculation when used as in the examples above, care
-
# should be taken to note that this is not true if the result of `months', `years', etc is
-
# converted before use:
-
#
-
# # equivalent to 30.days.to_i.from_now
-
# 1.month.to_i.from_now
-
#
-
# # equivalent to 365.25.days.to_f.from_now
-
# 1.year.to_f.from_now
-
#
-
# In such cases, Ruby's core
-
# Date[http://ruby-doc.org/stdlib/libdoc/date/rdoc/Date.html] and
-
# Time[http://ruby-doc.org/stdlib/libdoc/time/rdoc/Time.html] should be used for precision
-
# date and time arithmetic.
-
1
def seconds
-
ActiveSupport::Duration.new(self, [[:seconds, self]])
-
end
-
1
alias :second :seconds
-
-
1
def minutes
-
4
ActiveSupport::Duration.new(self * 60, [[:seconds, self * 60]])
-
end
-
1
alias :minute :minutes
-
-
1
def hours
-
35
ActiveSupport::Duration.new(self * 3600, [[:seconds, self * 3600]])
-
end
-
1
alias :hour :hours
-
-
1
def days
-
31
ActiveSupport::Duration.new(self * 24.hours, [[:days, self]])
-
end
-
1
alias :day :days
-
-
1
def weeks
-
21
ActiveSupport::Duration.new(self * 7.days, [[:days, self * 7]])
-
end
-
1
alias :week :weeks
-
-
1
def fortnights
-
ActiveSupport::Duration.new(self * 2.weeks, [[:days, self * 14]])
-
end
-
1
alias :fortnight :fortnights
-
-
# Reads best without arguments: 10.minutes.ago
-
1
def ago(time = ::Time.current)
-
time - self
-
end
-
-
# Reads best with argument: 10.minutes.until(time)
-
1
alias :until :ago
-
-
# Reads best with argument: 10.minutes.since(time)
-
1
def since(time = ::Time.current)
-
time + self
-
end
-
-
# Reads best without arguments: 10.minutes.from_now
-
1
alias :from_now :since
-
end
-
1
class Object
-
# A duck-type assistant method. For example, Active Support extends Date
-
# to define an acts_like_date? method, and extends Time to define
-
# acts_like_time?. As a result, we can do "x.acts_like?(:time)" and
-
# "x.acts_like?(:date)" to do duck-type-safe comparisons, since classes that
-
# we want to act like Time simply need to define an acts_like_time? method.
-
1
def acts_like?(duck)
-
6390
respond_to? :"acts_like_#{duck}?"
-
end
-
end
-
# encoding: utf-8
-
-
1
class Object
-
# An object is blank if it's false, empty, or a whitespace string.
-
# For example, '', ' ', +nil+, [], and {} are all blank.
-
#
-
# This simplifies:
-
#
-
# if address.nil? || address.empty?
-
#
-
# ...to:
-
#
-
# if address.blank?
-
1
def blank?
-
19864
respond_to?(:empty?) ? empty? : !self
-
end
-
-
# An object is present if it's not <tt>blank?</tt>.
-
1
def present?
-
11876
!blank?
-
end
-
-
# Returns object if it's <tt>present?</tt> otherwise returns +nil+.
-
# <tt>object.presence</tt> is equivalent to <tt>object.present? ? object : nil</tt>.
-
#
-
# This is handy for any representation of objects where blank is the same
-
# as not present at all. For example, this simplifies a common check for
-
# HTTP POST/query parameters:
-
#
-
# state = params[:state] if params[:state].present?
-
# country = params[:country] if params[:country].present?
-
# region = state || country || 'US'
-
#
-
# ...becomes:
-
#
-
# region = params[:state].presence || params[:country].presence || 'US'
-
1
def presence
-
1207
self if present?
-
end
-
end
-
-
1
class NilClass
-
# +nil+ is blank:
-
#
-
# nil.blank? # => true
-
1
def blank?
-
177694
true
-
end
-
end
-
-
1
class FalseClass
-
# +false+ is blank:
-
#
-
# false.blank? # => true
-
1
def blank?
-
true
-
end
-
end
-
-
1
class TrueClass
-
# +true+ is not blank:
-
#
-
# true.blank? # => false
-
1
def blank?
-
350
false
-
end
-
end
-
-
1
class Array
-
# An array is blank if it's empty:
-
#
-
# [].blank? # => true
-
# [1,2,3].blank? # => false
-
1
alias_method :blank?, :empty?
-
end
-
-
1
class Hash
-
# A hash is blank if it's empty:
-
#
-
# {}.blank? # => true
-
# { key: 'value' }.blank? # => false
-
1
alias_method :blank?, :empty?
-
end
-
-
1
class String
-
# A string is blank if it's empty or contains whitespaces only:
-
#
-
# ''.blank? # => true
-
# ' '.blank? # => true
-
# ' '.blank? # => true
-
# ' something here '.blank? # => false
-
1
def blank?
-
15318
self !~ /[^[:space:]]/
-
end
-
end
-
-
1
class Numeric #:nodoc:
-
# No number is blank:
-
#
-
# 1.blank? # => false
-
# 0.blank? # => false
-
1
def blank?
-
4704
false
-
end
-
end
-
#--
-
# Most objects are cloneable, but not all. For example you can't dup +nil+:
-
#
-
# nil.dup # => TypeError: can't dup NilClass
-
#
-
# Classes may signal their instances are not duplicable removing +dup+/+clone+
-
# or raising exceptions from them. So, to dup an arbitrary object you normally
-
# use an optimistic approach and are ready to catch an exception, say:
-
#
-
# arbitrary_object.dup rescue object
-
#
-
# Rails dups objects in a few critical spots where they are not that arbitrary.
-
# That rescue is very expensive (like 40 times slower than a predicate), and it
-
# is often triggered.
-
#
-
# That's why we hardcode the following cases and check duplicable? instead of
-
# using that rescue idiom.
-
#++
-
1
class Object
-
# Can you safely dup this object?
-
#
-
# False for +nil+, +false+, +true+, symbol, and number objects;
-
# true otherwise.
-
1
def duplicable?
-
1828
true
-
end
-
end
-
-
1
class NilClass
-
# +nil+ is not duplicable:
-
#
-
# nil.duplicable? # => false
-
# nil.dup # => TypeError: can't dup NilClass
-
1
def duplicable?
-
27924
false
-
end
-
end
-
-
1
class FalseClass
-
# +false+ is not duplicable:
-
#
-
# false.duplicable? # => false
-
# false.dup # => TypeError: can't dup FalseClass
-
1
def duplicable?
-
194
false
-
end
-
end
-
-
1
class TrueClass
-
# +true+ is not duplicable:
-
#
-
# true.duplicable? # => false
-
# true.dup # => TypeError: can't dup TrueClass
-
1
def duplicable?
-
440
false
-
end
-
end
-
-
1
class Symbol
-
# Symbols are not duplicable:
-
#
-
# :my_symbol.duplicable? # => false
-
# :my_symbol.dup # => TypeError: can't dup Symbol
-
1
def duplicable?
-
false
-
end
-
end
-
-
1
class Numeric
-
# Numbers are not duplicable:
-
#
-
# 3.duplicable? # => false
-
# 3.dup # => TypeError: can't dup Fixnum
-
1
def duplicable?
-
4673
false
-
end
-
end
-
-
1
require 'bigdecimal'
-
1
class BigDecimal
-
1
begin
-
1
BigDecimal.new('4.56').dup
-
-
def duplicable?
-
true
-
end
-
rescue TypeError
-
# can't dup, so use superclass implementation
-
end
-
end
-
1
class Object
-
# Returns a hash with string keys that maps instance variable names without "@" to their
-
# corresponding values.
-
#
-
# class C
-
# def initialize(x, y)
-
# @x, @y = x, y
-
# end
-
# end
-
#
-
# C.new(0, 1).instance_values # => {"x" => 0, "y" => 1}
-
1
def instance_values
-
Hash[instance_variables.map { |name| [name[1..-1], instance_variable_get(name)] }]
-
end
-
-
# Returns an array of instance variable names including "@".
-
#
-
# class C
-
# def initialize(x, y)
-
# @x, @y = x, y
-
# end
-
# end
-
#
-
# C.new(0, 1).instance_variable_names # => ["@y", "@x"]
-
1
def instance_variable_names
-
instance_variables.map { |var| var.to_s }
-
end
-
end
-
# Hack to load json gem first so we can overwrite its to_json.
-
1
begin
-
1
require 'json'
-
rescue LoadError
-
end
-
-
# The JSON gem adds a few modules to Ruby core classes containing :to_json definition, overwriting
-
# their default behavior. That said, we need to define the basic to_json method in all of them,
-
# otherwise they will always use to_json gem implementation, which is backwards incompatible in
-
# several cases (for instance, the JSON implementation for Hash does not work) with inheritance
-
# and consequently classes as ActiveSupport::OrderedHash cannot be serialized to json.
-
1
[Object, Array, FalseClass, Float, Hash, Integer, NilClass, String, TrueClass].each do |klass|
-
9
klass.class_eval do
-
# Dumps object in JSON (JavaScript Object Notation). See www.json.org for more info.
-
9
def to_json(options = nil)
-
68
ActiveSupport::JSON.encode(self, options)
-
end
-
end
-
end
-
-
1
module Process
-
1
class Status
-
1
def as_json(options = nil)
-
{ :exitstatus => exitstatus, :pid => pid }
-
end
-
end
-
end
-
1
class Object
-
# Alias of <tt>to_s</tt>.
-
1
def to_param
-
to_s
-
end
-
end
-
-
1
class NilClass
-
# Returns +self+.
-
1
def to_param
-
self
-
end
-
end
-
-
1
class TrueClass
-
# Returns +self+.
-
1
def to_param
-
self
-
end
-
end
-
-
1
class FalseClass
-
# Returns +self+.
-
1
def to_param
-
self
-
end
-
end
-
-
1
class Array
-
# Calls <tt>to_param</tt> on all its elements and joins the result with
-
# slashes. This is used by <tt>url_for</tt> in Action Pack.
-
1
def to_param
-
collect { |e| e.to_param }.join '/'
-
end
-
end
-
-
1
class Hash
-
# Returns a string representation of the receiver suitable for use as a URL
-
# query string:
-
#
-
# {name: 'David', nationality: 'Danish'}.to_param
-
# # => "name=David&nationality=Danish"
-
#
-
# An optional namespace can be passed to enclose the param names:
-
#
-
# {name: 'David', nationality: 'Danish'}.to_param('user')
-
# # => "user[name]=David&user[nationality]=Danish"
-
#
-
# The string pairs "key=value" that conform the query string
-
# are sorted lexicographically in ascending order.
-
#
-
# This method is also aliased as +to_query+.
-
1
def to_param(namespace = nil)
-
collect do |key, value|
-
value.to_query(namespace ? "#{namespace}[#{key}]" : key)
-
end.sort * '&'
-
end
-
end
-
1
require 'active_support/core_ext/object/to_param'
-
-
1
class Object
-
# Converts an object into a string suitable for use as a URL query string, using the given <tt>key</tt> as the
-
# param name.
-
#
-
# Note: This method is defined as a default implementation for all Objects for Hash#to_query to work.
-
1
def to_query(key)
-
require 'cgi' unless defined?(CGI) && defined?(CGI::escape)
-
"#{CGI.escape(key.to_param)}=#{CGI.escape(to_param.to_s)}"
-
end
-
end
-
-
1
class Array
-
# Converts an array into a string suitable for use as a URL query string,
-
# using the given +key+ as the param name.
-
#
-
# ['Rails', 'coding'].to_query('hobbies') # => "hobbies%5B%5D=Rails&hobbies%5B%5D=coding"
-
1
def to_query(key)
-
prefix = "#{key}[]"
-
collect { |value| value.to_query(prefix) }.join '&'
-
end
-
end
-
-
1
class Hash
-
1
alias_method :to_query, :to_param
-
end
-
1
class Object
-
# Invokes the public method identified by the symbol +method+, passing it any arguments
-
# and/or the block specified, just like the regular Ruby <tt>Object#public_send</tt> does.
-
#
-
# *Unlike* that method however, a +NoMethodError+ exception will *not* be raised
-
# and +nil+ will be returned instead, if the receiving object is a +nil+ object or NilClass.
-
#
-
# This is also true if the receiving object does not implemented the tried method. It will
-
# return +nil+ in that case as well.
-
#
-
# If try is called without a method to call, it will yield any given block with the object.
-
#
-
# Please also note that +try+ is defined on +Object+, therefore it won't work with
-
# subclasses of +BasicObject+. For example, using try with +SimpleDelegator+ will
-
# delegate +try+ to target instead of calling it on delegator itself.
-
#
-
# Without +try+
-
# @person && @person.name
-
# or
-
# @person ? @person.name : nil
-
#
-
# With +try+
-
# @person.try(:name)
-
#
-
# +try+ also accepts arguments and/or a block, for the method it is trying
-
# Person.try(:find, 1)
-
# @people.try(:collect) {|p| p.name}
-
#
-
# Without a method argument try will yield to the block unless the receiver is nil.
-
# @person.try { |p| "#{p.first_name} #{p.last_name}" }
-
#
-
# +try+ behaves like +Object#public_send+, unless called on +NilClass+.
-
1
def try(*a, &b)
-
7883
if a.empty? && block_given?
-
yield self
-
else
-
7883
public_send(*a, &b) if respond_to?(a.first)
-
end
-
end
-
-
# Same as #try, but will raise a NoMethodError exception if the receiving is not nil and
-
# does not implemented the tried method.
-
1
def try!(*a, &b)
-
if a.empty? && block_given?
-
yield self
-
else
-
public_send(*a, &b)
-
end
-
end
-
end
-
-
1
class NilClass
-
# Calling +try+ on +nil+ always returns +nil+.
-
# It becomes specially helpful when navigating through associations that may return +nil+.
-
#
-
# nil.try(:name) # => nil
-
#
-
# Without +try+
-
# @person && !@person.children.blank? && @person.children.first.name
-
#
-
# With +try+
-
# @person.try(:children).try(:first).try(:name)
-
1
def try(*args)
-
nil
-
end
-
-
1
def try!(*args)
-
nil
-
end
-
end
-
1
require 'active_support/option_merger'
-
-
1
class Object
-
# An elegant way to factor duplication out of options passed to a series of
-
# method calls. Each method called in the block, with the block variable as
-
# the receiver, will have its options merged with the default +options+ hash
-
# provided. Each method called on the block variable must take an options
-
# hash as its final argument.
-
#
-
# Without <tt>with_options></tt>, this code contains duplication:
-
#
-
# class Account < ActiveRecord::Base
-
# has_many :customers, dependent: :destroy
-
# has_many :products, dependent: :destroy
-
# has_many :invoices, dependent: :destroy
-
# has_many :expenses, dependent: :destroy
-
# end
-
#
-
# Using <tt>with_options</tt>, we can remove the duplication:
-
#
-
# class Account < ActiveRecord::Base
-
# with_options dependent: :destroy do |assoc|
-
# assoc.has_many :customers
-
# assoc.has_many :products
-
# assoc.has_many :invoices
-
# assoc.has_many :expenses
-
# end
-
# end
-
#
-
# It can also be used with an explicit receiver:
-
#
-
# I18n.with_options locale: user.locale, scope: 'newsletter' do |i18n|
-
# subject i18n.t :subject
-
# body i18n.t :body, user_name: user.name
-
# end
-
#
-
# <tt>with_options</tt> can also be nested since the call is forwarded to its receiver.
-
# Each nesting level will merge inherited defaults in addition to their own.
-
1
def with_options(options)
-
1
yield ActiveSupport::OptionMerger.new(self, options)
-
end
-
end
-
1
require 'active_support/core_ext/range/conversions'
-
1
require 'active_support/core_ext/range/include_range'
-
1
require 'active_support/core_ext/range/overlaps'
-
1
class Range
-
1
RANGE_FORMATS = {
-
:db => Proc.new { |start, stop| "BETWEEN '#{start.to_s(:db)}' AND '#{stop.to_s(:db)}'" }
-
}
-
-
# Gives a human readable format of the range.
-
#
-
# (1..100).to_formatted_s # => "1..100"
-
1
def to_formatted_s(format = :default)
-
if formatter = RANGE_FORMATS[format]
-
formatter.call(first, last)
-
else
-
to_default_s
-
end
-
end
-
-
1
alias_method :to_default_s, :to_s
-
1
alias_method :to_s, :to_formatted_s
-
end
-
1
class Range
-
# Extends the default Range#include? to support range comparisons.
-
# (1..5).include?(1..5) # => true
-
# (1..5).include?(2..3) # => true
-
# (1..5).include?(2..6) # => false
-
#
-
# The native Range#include? behavior is untouched.
-
# ('a'..'f').include?('c') # => true
-
# (5..9).include?(11) # => false
-
1
def include_with_range?(value)
-
17
if value.is_a?(::Range)
-
# 1...10 includes 1..9 but it does not include 1..10.
-
operator = exclude_end? && !value.exclude_end? ? :< : :<=
-
include_without_range?(value.first) && value.last.send(operator, last)
-
else
-
17
include_without_range?(value)
-
end
-
end
-
-
1
alias_method_chain :include?, :range
-
end
-
1
class Range
-
# Compare two ranges and see if they overlap each other
-
# (1..5).overlaps?(4..6) # => true
-
# (1..5).overlaps?(7..9) # => false
-
1
def overlaps?(other)
-
cover?(other.first) || other.cover?(first)
-
end
-
end
-
1
class String
-
# If you pass a single Fixnum, returns a substring of one character at that
-
# position. The first character of the string is at position 0, the next at
-
# position 1, and so on. If a range is supplied, a substring containing
-
# characters at offsets given by the range is returned. In both cases, if an
-
# offset is negative, it is counted from the end of the string. Returns nil
-
# if the initial offset falls outside the string. Returns an empty string if
-
# the beginning of the range is greater than the end of the string.
-
#
-
# str = "hello"
-
# str.at(0) #=> "h"
-
# str.at(1..3) #=> "ell"
-
# str.at(-2) #=> "l"
-
# str.at(-2..-1) #=> "lo"
-
# str.at(5) #=> nil
-
# str.at(5..-1) #=> ""
-
#
-
# If a Regexp is given, the matching portion of the string is returned.
-
# If a String is given, that given string is returned if it occurs in
-
# the string. In both cases, nil is returned if there is no match.
-
#
-
# str = "hello"
-
# str.at(/lo/) #=> "lo"
-
# str.at(/ol/) #=> nil
-
# str.at("lo") #=> "lo"
-
# str.at("ol") #=> nil
-
1
def at(position)
-
self[position]
-
end
-
-
# Returns a substring from the given position to the end of the string.
-
# If the position is negative, it is counted from the end of the string.
-
#
-
# str = "hello"
-
# str.from(0) #=> "hello"
-
# str.from(3) #=> "lo"
-
# str.from(-2) #=> "lo"
-
#
-
# You can mix it with +to+ method and do fun things like:
-
#
-
# str = "hello"
-
# str.from(0).to(-1) #=> "hello"
-
# str.from(1).to(-2) #=> "ell"
-
1
def from(position)
-
self[position..-1]
-
end
-
-
# Returns a substring from the beginning of the string to the given position.
-
# If the position is negative, it is counted from the end of the string.
-
#
-
# str = "hello"
-
# str.to(0) #=> "h"
-
# str.to(3) #=> "hell"
-
# str.to(-2) #=> "hell"
-
#
-
# You can mix it with +from+ method and do fun things like:
-
#
-
# str = "hello"
-
# str.from(0).to(-1) #=> "hello"
-
# str.from(1).to(-2) #=> "ell"
-
1
def to(position)
-
5
self[0..position]
-
end
-
-
# Returns the first character. If a limit is supplied, returns a substring
-
# from the beginning of the string until it reaches the limit value. If the
-
# given limit is greater than or equal to the string length, returns self.
-
#
-
# str = "hello"
-
# str.first #=> "h"
-
# str.first(1) #=> "h"
-
# str.first(2) #=> "he"
-
# str.first(0) #=> ""
-
# str.first(6) #=> "hello"
-
1
def first(limit = 1)
-
5
if limit == 0
-
''
-
5
elsif limit >= size
-
self
-
else
-
5
to(limit - 1)
-
end
-
end
-
-
# Returns the last character of the string. If a limit is supplied, returns a substring
-
# from the end of the string until it reaches the limit value (counting backwards). If
-
# the given limit is greater than or equal to the string length, returns self.
-
#
-
# str = "hello"
-
# str.last #=> "o"
-
# str.last(1) #=> "o"
-
# str.last(2) #=> "lo"
-
# str.last(0) #=> ""
-
# str.last(6) #=> "hello"
-
1
def last(limit = 1)
-
if limit == 0
-
''
-
elsif limit >= size
-
self
-
else
-
from(-limit)
-
end
-
end
-
end
-
1
class String
-
# Enable more predictable duck-typing on String-like classes. See <tt>Object#acts_like?</tt>.
-
1
def acts_like_string?
-
true
-
end
-
end
-
1
require 'date'
-
1
require 'active_support/core_ext/time/calculations'
-
-
1
class String
-
# Converts a string to a Time value.
-
# The +form+ can be either :utc or :local (default :utc).
-
#
-
# The time is parsed using Date._parse method.
-
# If +form+ is :local, then time is formatted using Time.zone
-
#
-
# "3-2-2012".to_time # => 2012-02-03 00:00:00 UTC
-
# "12:20".to_time # => ArgumentError: invalid date
-
# "2012-12-13 06:12".to_time # => 2012-12-13 06:12:00 UTC
-
# "2012-12-13T06:12".to_time # => 2012-12-13 06:12:00 UTC
-
# "2012-12-13T06:12".to_time(:local) # => 2012-12-13 06:12:00 +0100
-
1
def to_time(form = :utc)
-
unless blank?
-
date_values = ::Date._parse(self, false).
-
values_at(:year, :mon, :mday, :hour, :min, :sec, :sec_fraction, :offset).
-
map! { |arg| arg || 0 }
-
date_values[6] *= 1000000
-
offset = date_values.pop
-
-
::Time.send("#{form}_time", *date_values) - offset
-
end
-
end
-
-
# Converts a string to a Date value.
-
#
-
# "1-1-2012".to_date #=> Sun, 01 Jan 2012
-
# "01/01/2012".to_date #=> Sun, 01 Jan 2012
-
# "2012-12-13".to_date #=> Thu, 13 Dec 2012
-
# "12/13/2012".to_date #=> ArgumentError: invalid date
-
1
def to_date
-
unless blank?
-
date_values = ::Date._parse(self, false).values_at(:year, :mon, :mday)
-
-
::Date.new(*date_values)
-
end
-
end
-
-
# Converts a string to a DateTime value.
-
#
-
# "1-1-2012".to_datetime #=> Sun, 01 Jan 2012 00:00:00 +0000
-
# "01/01/2012 23:59:59".to_datetime #=> Sun, 01 Jan 2012 23:59:59 +0000
-
# "2012-12-13 12:50".to_datetime #=> Thu, 13 Dec 2012 12:50:00 +0000
-
# "12/13/2012".to_datetime #=> ArgumentError: invalid date
-
1
def to_datetime
-
622
unless blank?
-
622
date_values = ::Date._parse(self, false).
-
values_at(:year, :mon, :mday, :hour, :min, :sec, :zone, :sec_fraction).
-
4976
map! { |arg| arg || 0 }
-
622
date_values[5] += date_values.pop
-
-
622
::DateTime.civil(*date_values)
-
end
-
end
-
end
-
1
require 'active_support/inflector/methods'
-
1
require 'active_support/inflector/transliterate'
-
-
# String inflections define new methods on the String class to transform names for different purposes.
-
# For instance, you can figure out the name of a table from the name of a class.
-
#
-
# 'ScaleScore'.tableize # => "scale_scores"
-
#
-
1
class String
-
# Returns the plural form of the word in the string.
-
#
-
# If the optional parameter +count+ is specified,
-
# the singular form will be returned if <tt>count == 1</tt>.
-
# For any other value of +count+ the plural will be returned.
-
#
-
# If the optional parameter +locale+ is specified,
-
# the word will be pluralized as a word of that language.
-
# By default, this parameter is set to <tt>:en</tt>.
-
# You must define your own inflection rules for languages other than English.
-
#
-
# 'post'.pluralize # => "posts"
-
# 'octopus'.pluralize # => "octopi"
-
# 'sheep'.pluralize # => "sheep"
-
# 'words'.pluralize # => "words"
-
# 'the blue mailman'.pluralize # => "the blue mailmen"
-
# 'CamelOctopus'.pluralize # => "CamelOctopi"
-
# 'apple'.pluralize(1) # => "apple"
-
# 'apple'.pluralize(2) # => "apples"
-
# 'ley'.pluralize(:es) # => "leyes"
-
# 'ley'.pluralize(1, :es) # => "ley"
-
1
def pluralize(count = nil, locale = :en)
-
991
locale = count if count.is_a?(Symbol)
-
991
if count == 1
-
self
-
else
-
991
ActiveSupport::Inflector.pluralize(self, locale)
-
end
-
end
-
-
# The reverse of +pluralize+, returns the singular form of a word in a string.
-
#
-
# If the optional parameter +locale+ is specified,
-
# the word will be singularized as a word of that language.
-
# By default, this paramter is set to <tt>:en</tt>.
-
# You must define your own inflection rules for languages other than English.
-
#
-
# 'posts'.singularize # => "post"
-
# 'octopi'.singularize # => "octopus"
-
# 'sheep'.singularize # => "sheep"
-
# 'word'.singularize # => "word"
-
# 'the blue mailmen'.singularize # => "the blue mailman"
-
# 'CamelOctopi'.singularize # => "CamelOctopus"
-
# 'leyes'.singularize(:es) # => "ley"
-
1
def singularize(locale = :en)
-
2588
ActiveSupport::Inflector.singularize(self, locale)
-
end
-
-
# +constantize+ tries to find a declared constant with the name specified
-
# in the string. It raises a NameError when the name is not in CamelCase
-
# or is not initialized. See ActiveSupport::Inflector.constantize
-
#
-
# 'Module'.constantize # => Module
-
# 'Class'.constantize # => Class
-
# 'blargle'.constantize # => NameError: wrong constant name blargle
-
1
def constantize
-
2937
ActiveSupport::Inflector.constantize(self)
-
end
-
-
# +safe_constantize+ tries to find a declared constant with the name specified
-
# in the string. It returns nil when the name is not in CamelCase
-
# or is not initialized. See ActiveSupport::Inflector.safe_constantize
-
#
-
# 'Module'.safe_constantize # => Module
-
# 'Class'.safe_constantize # => Class
-
# 'blargle'.safe_constantize # => nil
-
1
def safe_constantize
-
16
ActiveSupport::Inflector.safe_constantize(self)
-
end
-
-
# By default, +camelize+ converts strings to UpperCamelCase. If the argument to camelize
-
# is set to <tt>:lower</tt> then camelize produces lowerCamelCase.
-
#
-
# +camelize+ will also convert '/' to '::' which is useful for converting paths to namespaces.
-
#
-
# 'active_record'.camelize # => "ActiveRecord"
-
# 'active_record'.camelize(:lower) # => "activeRecord"
-
# 'active_record/errors'.camelize # => "ActiveRecord::Errors"
-
# 'active_record/errors'.camelize(:lower) # => "activeRecord::Errors"
-
1
def camelize(first_letter = :upper)
-
1161
case first_letter
-
when :upper
-
1161
ActiveSupport::Inflector.camelize(self, true)
-
when :lower
-
ActiveSupport::Inflector.camelize(self, false)
-
end
-
end
-
1
alias_method :camelcase, :camelize
-
-
# Capitalizes all the words and replaces some characters in the string to create
-
# a nicer looking title. +titleize+ is meant for creating pretty output. It is not
-
# used in the Rails internals.
-
#
-
# +titleize+ is also aliased as +titlecase+.
-
#
-
# 'man from the boondocks'.titleize # => "Man From The Boondocks"
-
# 'x-men: the last stand'.titleize # => "X Men: The Last Stand"
-
1
def titleize
-
2
ActiveSupport::Inflector.titleize(self)
-
end
-
1
alias_method :titlecase, :titleize
-
-
# The reverse of +camelize+. Makes an underscored, lowercase form from the expression in the string.
-
#
-
# +underscore+ will also change '::' to '/' to convert namespaces to paths.
-
#
-
# 'ActiveModel'.underscore # => "active_model"
-
# 'ActiveModel::Errors'.underscore # => "active_model/errors"
-
1
def underscore
-
1073
ActiveSupport::Inflector.underscore(self)
-
end
-
-
# Replaces underscores with dashes in the string.
-
#
-
# 'puni_puni'.dasherize # => "puni-puni"
-
1
def dasherize
-
1
ActiveSupport::Inflector.dasherize(self)
-
end
-
-
# Removes the module part from the constant expression in the string.
-
#
-
# 'ActiveRecord::CoreExtensions::String::Inflections'.demodulize # => "Inflections"
-
# 'Inflections'.demodulize # => "Inflections"
-
#
-
# See also +deconstantize+.
-
1
def demodulize
-
407
ActiveSupport::Inflector.demodulize(self)
-
end
-
-
# Removes the rightmost segment from the constant expression in the string.
-
#
-
# 'Net::HTTP'.deconstantize # => "Net"
-
# '::Net::HTTP'.deconstantize # => "::Net"
-
# 'String'.deconstantize # => ""
-
# '::String'.deconstantize # => ""
-
# ''.deconstantize # => ""
-
#
-
# See also +demodulize+.
-
1
def deconstantize
-
ActiveSupport::Inflector.deconstantize(self)
-
end
-
-
# Replaces special characters in a string so that it may be used as part of a 'pretty' URL.
-
#
-
# class Person
-
# def to_param
-
# "#{id}-#{name.parameterize}"
-
# end
-
# end
-
#
-
# @person = Person.find(1)
-
# # => #<Person id: 1, name: "Donald E. Knuth">
-
#
-
# <%= link_to(@person.name, person_path) %>
-
# # => <a href="/person/1-donald-e-knuth">Donald E. Knuth</a>
-
1
def parameterize(sep = '-')
-
ActiveSupport::Inflector.parameterize(self, sep)
-
end
-
-
# Creates the name of a table like Rails does for models to table names. This method
-
# uses the +pluralize+ method on the last word in the string.
-
#
-
# 'RawScaledScorer'.tableize # => "raw_scaled_scorers"
-
# 'egg_and_ham'.tableize # => "egg_and_hams"
-
# 'fancyCategory'.tableize # => "fancy_categories"
-
1
def tableize
-
ActiveSupport::Inflector.tableize(self)
-
end
-
-
# Create a class name from a plural table name like Rails does for table names to models.
-
# Note that this returns a string and not a class. (To convert to an actual class
-
# follow +classify+ with +constantize+.)
-
#
-
# 'egg_and_hams'.classify # => "EggAndHam"
-
# 'posts'.classify # => "Post"
-
#
-
# Singular names are not handled correctly.
-
#
-
# 'business'.classify # => "Busines"
-
1
def classify
-
11
ActiveSupport::Inflector.classify(self)
-
end
-
-
# Capitalizes the first word, turns underscores into spaces, and strips '_id'.
-
# Like +titleize+, this is meant for creating pretty output.
-
#
-
# 'employee_salary' # => "Employee salary"
-
# 'author_id' # => "Author"
-
1
def humanize
-
341
ActiveSupport::Inflector.humanize(self)
-
end
-
-
# Creates a foreign key name from a class name.
-
# +separate_class_name_and_id_with_underscore+ sets whether
-
# the method should put '_' between the name and 'id'.
-
#
-
# 'Message'.foreign_key # => "message_id"
-
# 'Message'.foreign_key(false) # => "messageid"
-
# 'Admin::Post'.foreign_key # => "post_id"
-
1
def foreign_key(separate_class_name_and_id_with_underscore = true)
-
223
ActiveSupport::Inflector.foreign_key(self, separate_class_name_and_id_with_underscore)
-
end
-
end
-
# encoding: utf-8
-
1
require 'active_support/multibyte'
-
-
1
class String
-
# == Multibyte proxy
-
#
-
# +mb_chars+ is a multibyte safe proxy for string methods.
-
#
-
# In Ruby 1.8 and older it creates and returns an instance of the ActiveSupport::Multibyte::Chars class which
-
# encapsulates the original string. A Unicode safe version of all the String methods are defined on this proxy
-
# class. If the proxy class doesn't respond to a certain method, it's forwarded to the encapsulated string.
-
#
-
# name = 'Claus Müller'
-
# name.reverse # => "rell??M sualC"
-
# name.length # => 13
-
#
-
# name.mb_chars.reverse.to_s # => "rellüM sualC"
-
# name.mb_chars.length # => 12
-
#
-
# In Ruby 1.9 and newer +mb_chars+ returns +self+ because String is (mostly) encoding aware. This means that
-
# it becomes easy to run one version of your code on multiple Ruby versions.
-
#
-
# == Method chaining
-
#
-
# All the methods on the Chars proxy which normally return a string will return a Chars object. This allows
-
# method chaining on the result of any of these methods.
-
#
-
# name.mb_chars.reverse.length # => 12
-
#
-
# == Interoperability and configuration
-
#
-
# The Chars object tries to be as interchangeable with String objects as possible: sorting and comparing between
-
# String and Char work like expected. The bang! methods change the internal string representation in the Chars
-
# object. Interoperability problems can be resolved easily with a +to_s+ call.
-
#
-
# For more information about the methods defined on the Chars proxy see ActiveSupport::Multibyte::Chars. For
-
# information about how to change the default Multibyte behavior see ActiveSupport::Multibyte.
-
1
def mb_chars
-
6
if ActiveSupport::Multibyte.proxy_class.consumes?(self)
-
ActiveSupport::Multibyte.proxy_class.new(self)
-
else
-
6
self
-
end
-
end
-
-
1
def is_utf8?
-
case encoding
-
when Encoding::UTF_8
-
valid_encoding?
-
when Encoding::ASCII_8BIT, Encoding::US_ASCII
-
dup.force_encoding(Encoding::UTF_8).valid_encoding?
-
else
-
false
-
end
-
end
-
end
-
1
class String
-
1
alias_method :starts_with?, :start_with?
-
1
alias_method :ends_with?, :end_with?
-
end
-
1
require 'active_support/core_ext/object/try'
-
-
1
class String
-
# Strips indentation in heredocs.
-
#
-
# For example in
-
#
-
# if options[:usage]
-
# puts <<-USAGE.strip_heredoc
-
# This command does such and such.
-
#
-
# Supported options are:
-
# -h This message
-
# ...
-
# USAGE
-
# end
-
#
-
# the user would see the usage message aligned against the left margin.
-
#
-
# Technically, it looks for the least indented line in the whole string, and removes
-
# that amount of leading whitespace.
-
1
def strip_heredoc
-
1
indent = scan(/^[ \t]*(?=\S)/).min.try(:size) || 0
-
1
gsub(/^[ \t]{#{indent}}/, '')
-
end
-
end
-
1
require 'active_support/core_ext/object/acts_like'
-
-
1
class Time
-
# Duck-types as a Time-like class. See Object#acts_like?.
-
1
def acts_like_time?
-
true
-
end
-
end
-
1
require 'active_support/duration'
-
1
require 'active_support/core_ext/time/conversions'
-
1
require 'active_support/time_with_zone'
-
1
require 'active_support/core_ext/time/zones'
-
1
require 'active_support/core_ext/date_and_time/calculations'
-
-
1
class Time
-
1
include DateAndTime::Calculations
-
-
1
COMMON_YEAR_DAYS_IN_MONTH = [nil, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31]
-
-
1
class << self
-
# Overriding case equality method so that it returns true for ActiveSupport::TimeWithZone instances
-
1
def ===(other)
-
3896
super || (self == Time && other.is_a?(ActiveSupport::TimeWithZone))
-
end
-
-
# Return the number of days in the given month.
-
# If no year is specified, it will use the current year.
-
1
def days_in_month(month, year = now.year)
-
if month == 2 && ::Date.gregorian_leap?(year)
-
29
-
else
-
COMMON_YEAR_DAYS_IN_MONTH[month]
-
end
-
end
-
-
# Returns a new Time if requested year can be accommodated by Ruby's Time class
-
# (i.e., if year is within either 1970..2038 or 1902..2038, depending on system architecture);
-
# otherwise returns a DateTime.
-
1
def time_with_datetime_fallback(utc_or_local, year, month=1, day=1, hour=0, min=0, sec=0, usec=0)
-
1258
time = ::Time.send(utc_or_local, year, month, day, hour, min, sec, usec)
-
-
# This check is needed because Time.utc(y) returns a time object in the 2000s for 0 <= y <= 138.
-
1257
if time.year == year
-
1257
time
-
else
-
::DateTime.civil_from_format(utc_or_local, year, month, day, hour, min, sec)
-
end
-
rescue
-
1
::DateTime.civil_from_format(utc_or_local, year, month, day, hour, min, sec)
-
end
-
-
# Wraps class method +time_with_datetime_fallback+ with +utc_or_local+ set to <tt>:utc</tt>.
-
1
def utc_time(*args)
-
60
time_with_datetime_fallback(:utc, *args)
-
end
-
-
# Wraps class method +time_with_datetime_fallback+ with +utc_or_local+ set to <tt>:local</tt>.
-
1
def local_time(*args)
-
3
time_with_datetime_fallback(:local, *args)
-
end
-
-
# Returns <tt>Time.zone.now</tt> when <tt>Time.zone</tt> or <tt>config.time_zone</tt> are set, otherwise just returns <tt>Time.now</tt>.
-
1
def current
-
29
::Time.zone ? ::Time.zone.now : ::Time.now
-
end
-
end
-
-
# Seconds since midnight: Time.now.seconds_since_midnight
-
1
def seconds_since_midnight
-
to_i - change(:hour => 0).to_i + (usec / 1.0e+6)
-
end
-
-
# Returns a new Time where one or more of the elements have been changed according
-
# to the +options+ parameter. The time options (<tt>:hour</tt>, <tt>:min</tt>,
-
# <tt>:sec</tt>, <tt>:usec</tt>) reset cascadingly, so if only the hour is passed,
-
# then minute, sec, and usec is set to 0. If the hour and minute is passed, then
-
# sec and usec is set to 0. The +options+ parameter takes a hash with any of these
-
# keys: <tt>:year</tt>, <tt>:month</tt>, <tt>:day</tt>, <tt>:hour</tt>, <tt>:min</tt>,
-
# <tt>:sec</tt>, <tt>:usec</tt>.
-
#
-
# Time.new(2012, 8, 29, 22, 35, 0).change(day: 1) # => Time.new(2012, 8, 1, 22, 35, 0)
-
# Time.new(2012, 8, 29, 22, 35, 0).change(year: 1981, day: 1) # => Time.new(1981, 8, 1, 22, 35, 0)
-
# Time.new(2012, 8, 29, 22, 35, 0).change(year: 1981, hour: 0) # => Time.new(1981, 8, 29, 0, 0, 0)
-
1
def change(options)
-
130
new_year = options.fetch(:year, year)
-
130
new_month = options.fetch(:month, month)
-
130
new_day = options.fetch(:day, day)
-
130
new_hour = options.fetch(:hour, hour)
-
130
new_min = options.fetch(:min, options[:hour] ? 0 : min)
-
130
new_sec = options.fetch(:sec, (options[:hour] || options[:min]) ? 0 : sec)
-
130
new_usec = options.fetch(:usec, (options[:hour] || options[:min] || options[:sec]) ? 0 : Rational(nsec, 1000))
-
-
130
if utc?
-
67
::Time.utc(new_year, new_month, new_day, new_hour, new_min, new_sec, new_usec)
-
63
elsif zone
-
63
::Time.local(new_year, new_month, new_day, new_hour, new_min, new_sec, new_usec)
-
else
-
::Time.new(new_year, new_month, new_day, new_hour, new_min, new_sec + (new_usec.to_r / 1000000), utc_offset)
-
end
-
end
-
-
# Uses Date to provide precise Time calculations for years, months, and days.
-
# The +options+ parameter takes a hash with any of these keys: <tt>:years</tt>,
-
# <tt>:months</tt>, <tt>:weeks</tt>, <tt>:days</tt>, <tt>:hours</tt>,
-
# <tt>:minutes</tt>, <tt>:seconds</tt>.
-
1
def advance(options)
-
62
unless options[:weeks].nil?
-
options[:weeks], partial_weeks = options[:weeks].divmod(1)
-
options[:days] = options.fetch(:days, 0) + 7 * partial_weeks
-
end
-
-
62
unless options[:days].nil?
-
30
options[:days], partial_days = options[:days].divmod(1)
-
30
options[:hours] = options.fetch(:hours, 0) + 24 * partial_days
-
end
-
-
62
d = to_date.advance(options)
-
62
time_advanced_by_date = change(:year => d.year, :month => d.month, :day => d.day)
-
62
seconds_to_advance = \
-
options.fetch(:seconds, 0) +
-
options.fetch(:minutes, 0) * 60 +
-
options.fetch(:hours, 0) * 3600
-
-
62
if seconds_to_advance.zero?
-
62
time_advanced_by_date
-
else
-
time_advanced_by_date.since(seconds_to_advance)
-
end
-
end
-
-
# Returns a new Time representing the time a number of seconds ago, this is basically a wrapper around the Numeric extension
-
1
def ago(seconds)
-
since(-seconds)
-
end
-
-
# Returns a new Time representing the time a number of seconds since the instance time
-
1
def since(seconds)
-
4
self + seconds
-
rescue
-
to_datetime.since(seconds)
-
end
-
1
alias :in :since
-
-
# Returns a new Time representing the start of the day (0:00)
-
1
def beginning_of_day
-
#(self - seconds_since_midnight).change(usec: 0)
-
2
change(:hour => 0)
-
end
-
1
alias :midnight :beginning_of_day
-
1
alias :at_midnight :beginning_of_day
-
1
alias :at_beginning_of_day :beginning_of_day
-
-
# Returns a new Time representing the end of the day, 23:59:59.999999 (.999999999 in ruby1.9)
-
1
def end_of_day
-
change(
-
:hour => 23,
-
:min => 59,
-
:sec => 59,
-
:usec => Rational(999999999, 1000)
-
)
-
end
-
-
# Returns a new Time representing the start of the hour (x:00)
-
1
def beginning_of_hour
-
change(:min => 0)
-
end
-
1
alias :at_beginning_of_hour :beginning_of_hour
-
-
# Returns a new Time representing the end of the hour, x:59:59.999999 (.999999999 in ruby1.9)
-
1
def end_of_hour
-
change(
-
:min => 59,
-
:sec => 59,
-
:usec => Rational(999999999, 1000)
-
)
-
end
-
-
# Returns a Range representing the whole day of the current time.
-
1
def all_day
-
beginning_of_day..end_of_day
-
end
-
-
# Returns a Range representing the whole week of the current time.
-
# Week starts on start_day, default is <tt>Date.week_start</tt> or <tt>config.week_start</tt> when set.
-
1
def all_week(start_day = Date.beginning_of_week)
-
beginning_of_week(start_day)..end_of_week(start_day)
-
end
-
-
# Returns a Range representing the whole month of the current time.
-
1
def all_month
-
beginning_of_month..end_of_month
-
end
-
-
# Returns a Range representing the whole quarter of the current time.
-
1
def all_quarter
-
beginning_of_quarter..end_of_quarter
-
end
-
-
# Returns a Range representing the whole year of the current time.
-
1
def all_year
-
beginning_of_year..end_of_year
-
end
-
-
1
def plus_with_duration(other) #:nodoc:
-
149
if ActiveSupport::Duration === other
-
2
other.since(self)
-
else
-
147
plus_without_duration(other)
-
end
-
end
-
1
alias_method :plus_without_duration, :+
-
1
alias_method :+, :plus_with_duration
-
-
1
def minus_with_duration(other) #:nodoc:
-
264449
if ActiveSupport::Duration === other
-
4
other.until(self)
-
else
-
264445
minus_without_duration(other)
-
end
-
end
-
1
alias_method :minus_without_duration, :-
-
1
alias_method :-, :minus_with_duration
-
-
# Time#- can also be used to determine the number of seconds between two Time instances.
-
# We're layering on additional behavior so that ActiveSupport::TimeWithZone instances
-
# are coerced into values that Time#- will recognize
-
1
def minus_with_coercion(other)
-
264449
other = other.comparable_time if other.respond_to?(:comparable_time)
-
264449
other.is_a?(DateTime) ? to_f - other.to_f : minus_without_coercion(other)
-
end
-
1
alias_method :minus_without_coercion, :-
-
1
alias_method :-, :minus_with_coercion
-
-
# Layers additional behavior on Time#<=> so that DateTime and ActiveSupport::TimeWithZone instances
-
# can be chronologically compared with a Time
-
1
def compare_with_coercion(other)
-
# we're avoiding Time#to_datetime cause it's expensive
-
2474
if other.is_a?(Time)
-
1707
compare_without_coercion(other.to_time)
-
else
-
767
to_datetime <=> other
-
end
-
end
-
1
alias_method :compare_without_coercion, :<=>
-
1
alias_method :<=>, :compare_with_coercion
-
-
# Layers additional behavior on Time#eql? so that ActiveSupport::TimeWithZone instances
-
# can be eql? to an equivalent Time
-
1
def eql_with_coercion(other)
-
# if other is an ActiveSupport::TimeWithZone, coerce a Time instance from it so we can do eql? comparison
-
other = other.comparable_time if other.respond_to?(:comparable_time)
-
eql_without_coercion(other)
-
end
-
1
alias_method :eql_without_coercion, :eql?
-
1
alias_method :eql?, :eql_with_coercion
-
-
end
-
1
require 'active_support/inflector/methods'
-
1
require 'active_support/values/time_zone'
-
-
1
class Time
-
1
DATE_FORMATS = {
-
:db => '%Y-%m-%d %H:%M:%S',
-
:number => '%Y%m%d%H%M%S',
-
:nsec => '%Y%m%d%H%M%S%9N',
-
:time => '%H:%M',
-
:short => '%d %b %H:%M',
-
:long => '%B %d, %Y %H:%M',
-
:long_ordinal => lambda { |time|
-
day_format = ActiveSupport::Inflector.ordinalize(time.day)
-
time.strftime("%B #{day_format}, %Y %H:%M")
-
},
-
:rfc822 => lambda { |time|
-
1
offset_format = time.formatted_offset(false)
-
1
time.strftime("%a, %d %b %Y %H:%M:%S #{offset_format}")
-
}
-
}
-
-
# Converts to a formatted string. See DATE_FORMATS for builtin formats.
-
#
-
# This method is aliased to <tt>to_s</tt>.
-
#
-
# time = Time.now # => Thu Jan 18 06:10:17 CST 2007
-
#
-
# time.to_formatted_s(:time) # => "06:10"
-
# time.to_s(:time) # => "06:10"
-
#
-
# time.to_formatted_s(:db) # => "2007-01-18 06:10:17"
-
# time.to_formatted_s(:number) # => "20070118061017"
-
# time.to_formatted_s(:short) # => "18 Jan 06:10"
-
# time.to_formatted_s(:long) # => "January 18, 2007 06:10"
-
# time.to_formatted_s(:long_ordinal) # => "January 18th, 2007 06:10"
-
# time.to_formatted_s(:rfc822) # => "Thu, 18 Jan 2007 06:10:17 -0600"
-
#
-
# == Adding your own time formats to +to_formatted_s+
-
# You can add your own formats to the Time::DATE_FORMATS hash.
-
# Use the format name as the hash key and either a strftime string
-
# or Proc instance that takes a time argument as the value.
-
#
-
# # config/initializers/time_formats.rb
-
# Time::DATE_FORMATS[:month_and_year] = '%B %Y'
-
# Time::DATE_FORMATS[:short_ordinal] = ->(time) { time.strftime("%B #{time.day.ordinalize}") }
-
1
def to_formatted_s(format = :default)
-
3818
if formatter = DATE_FORMATS[format]
-
3818
formatter.respond_to?(:call) ? formatter.call(self).to_s : strftime(formatter)
-
else
-
to_default_s
-
end
-
end
-
1
alias_method :to_default_s, :to_s
-
1
alias_method :to_s, :to_formatted_s
-
-
# Returns the UTC offset as an +HH:MM formatted string.
-
#
-
# Time.local(2000).formatted_offset # => "-06:00"
-
# Time.local(2000).formatted_offset(false) # => "-0600"
-
1
def formatted_offset(colon = true, alternate_utc_string = nil)
-
utc? && alternate_utc_string || ActiveSupport::TimeZone.seconds_to_utc_offset(utc_offset, colon)
-
end
-
end
-
# Ruby 1.9.2 adds utc_offset and zone to Time, but marshaling only
-
# preserves utc_offset. Preserve zone also, even though it may not
-
# work in some edge cases.
-
1
if Time.local(2010).zone != Marshal.load(Marshal.dump(Time.local(2010))).zone
-
1
class Time
-
1
class << self
-
1
alias_method :_load_without_zone, :_load
-
1
def _load(marshaled_time)
-
time = _load_without_zone(marshaled_time)
-
time.instance_eval do
-
if zone = defined?(@_zone) && remove_instance_variable('@_zone')
-
ary = to_a
-
ary[0] += subsec if ary[0] == sec
-
ary[-1] = zone
-
utc? ? Time.utc(*ary) : Time.local(*ary)
-
else
-
self
-
end
-
end
-
end
-
end
-
-
1
alias_method :_dump_without_zone, :_dump
-
1
def _dump(*args)
-
obj = dup
-
obj.instance_variable_set('@_zone', zone)
-
obj._dump_without_zone(*args)
-
end
-
end
-
end
-
1
require 'active_support/time_with_zone'
-
-
1
class Time
-
1
@zone_default = nil
-
-
1
class << self
-
1
attr_accessor :zone_default
-
-
# Returns the TimeZone for the current request, if this has been set (via Time.zone=).
-
# If <tt>Time.zone</tt> has not been set for the current request, returns the TimeZone specified in <tt>config.time_zone</tt>.
-
1
def zone
-
349
Thread.current[:time_zone] || zone_default
-
end
-
-
# Sets <tt>Time.zone</tt> to a TimeZone object for the current request/thread.
-
#
-
# This method accepts any of the following:
-
#
-
# * A Rails TimeZone object.
-
# * An identifier for a Rails TimeZone object (e.g., "Eastern Time (US & Canada)", <tt>-5.hours</tt>).
-
# * A TZInfo::Timezone object.
-
# * An identifier for a TZInfo::Timezone object (e.g., "America/New_York").
-
#
-
# Here's an example of how you might set <tt>Time.zone</tt> on a per request basis and reset it when the request is done.
-
# <tt>current_user.time_zone</tt> just needs to return a string identifying the user's preferred time zone:
-
#
-
# class ApplicationController < ActionController::Base
-
# around_filter :set_time_zone
-
#
-
# def set_time_zone
-
# if logged_in?
-
# Time.use_zone(current_user.time_zone) { yield }
-
# else
-
# yield
-
# end
-
# end
-
# end
-
1
def zone=(time_zone)
-
321
Thread.current[:time_zone] = find_zone!(time_zone)
-
end
-
-
# Allows override of <tt>Time.zone</tt> locally inside supplied block; resets <tt>Time.zone</tt> to existing value when done.
-
1
def use_zone(time_zone)
-
2
new_zone = find_zone!(time_zone)
-
2
begin
-
2
old_zone, ::Time.zone = ::Time.zone, new_zone
-
2
yield
-
ensure
-
2
::Time.zone = old_zone
-
end
-
end
-
-
# Returns a TimeZone instance or nil, or raises an ArgumentError for invalid timezones.
-
1
def find_zone!(time_zone)
-
541
if !time_zone || time_zone.is_a?(ActiveSupport::TimeZone)
-
508
time_zone
-
else
-
# lookup timezone based on identifier (unless we've been passed a TZInfo::Timezone)
-
33
unless time_zone.respond_to?(:period_for_local)
-
33
time_zone = ActiveSupport::TimeZone[time_zone] || TZInfo::Timezone.get(time_zone)
-
end
-
-
# Return if a TimeZone instance, or wrap in a TimeZone instance if a TZInfo::Timezone
-
33
if time_zone.is_a?(ActiveSupport::TimeZone)
-
33
time_zone
-
else
-
ActiveSupport::TimeZone.create(time_zone.name, nil, time_zone)
-
end
-
end
-
rescue TZInfo::InvalidTimezoneIdentifier
-
raise ArgumentError, "Invalid Timezone: #{time_zone}"
-
end
-
-
1
def find_zone(time_zone)
-
find_zone!(time_zone) rescue nil
-
end
-
end
-
-
# Returns the simultaneous time in <tt>Time.zone</tt>.
-
#
-
# Time.zone = 'Hawaii' # => 'Hawaii'
-
# Time.utc(2000).in_time_zone # => Fri, 31 Dec 1999 14:00:00 HST -10:00
-
#
-
# This method is similar to Time#localtime, except that it uses <tt>Time.zone</tt> as the local zone
-
# instead of the operating system's time zone.
-
#
-
# You can also pass in a TimeZone instance or string that identifies a TimeZone as an argument,
-
# and the conversion will be based on that zone instead of <tt>Time.zone</tt>.
-
#
-
# Time.utc(2000).in_time_zone('Alaska') # => Fri, 31 Dec 1999 15:00:00 AKST -09:00
-
1
def in_time_zone(zone = ::Time.zone)
-
264
if zone
-
218
ActiveSupport::TimeWithZone.new(utc? ? self : getutc, ::Time.find_zone!(zone))
-
else
-
46
self
-
end
-
end
-
end
-
1
require 'set'
-
1
require 'thread'
-
1
require 'pathname'
-
1
require 'active_support/core_ext/module/aliasing'
-
1
require 'active_support/core_ext/module/attribute_accessors'
-
1
require 'active_support/core_ext/module/introspection'
-
1
require 'active_support/core_ext/module/anonymous'
-
1
require 'active_support/core_ext/module/qualified_const'
-
1
require 'active_support/core_ext/object/blank'
-
1
require 'active_support/core_ext/load_error'
-
1
require 'active_support/core_ext/name_error'
-
1
require 'active_support/core_ext/string/starts_ends_with'
-
1
require 'active_support/inflector'
-
-
1
module ActiveSupport #:nodoc:
-
1
module Dependencies #:nodoc:
-
1
extend self
-
-
# Should we turn on Ruby warnings on the first load of dependent files?
-
1
mattr_accessor :warnings_on_first_load
-
1
self.warnings_on_first_load = false
-
-
# All files ever loaded.
-
1
mattr_accessor :history
-
1
self.history = Set.new
-
-
# All files currently loaded.
-
1
mattr_accessor :loaded
-
1
self.loaded = Set.new
-
-
# Should we load files or require them?
-
1
mattr_accessor :mechanism
-
1
self.mechanism = ENV['NO_RELOAD'] ? :require : :load
-
-
# The set of directories from which we may automatically load files. Files
-
# under these directories will be reloaded on each request in development mode,
-
# unless the directory also appears in autoload_once_paths.
-
1
mattr_accessor :autoload_paths
-
1
self.autoload_paths = []
-
-
# The set of directories from which automatically loaded constants are loaded
-
# only once. All directories in this set must also be present in +autoload_paths+.
-
1
mattr_accessor :autoload_once_paths
-
1
self.autoload_once_paths = []
-
-
# An array of qualified constant names that have been loaded. Adding a name
-
# to this array will cause it to be unloaded the next time Dependencies are
-
# cleared.
-
1
mattr_accessor :autoloaded_constants
-
1
self.autoloaded_constants = []
-
-
# An array of constant names that need to be unloaded on every request. Used
-
# to allow arbitrary constants to be marked for unloading.
-
1
mattr_accessor :explicitly_unloadable_constants
-
1
self.explicitly_unloadable_constants = []
-
-
# The logger is used for generating information on the action run-time
-
# (including benchmarking) if available. Can be set to nil for no logging.
-
# Compatible with both Ruby's own Logger and Log4r loggers.
-
1
mattr_accessor :logger
-
-
# Set to +true+ to enable logging of const_missing and file loads.
-
1
mattr_accessor :log_activity
-
1
self.log_activity = false
-
-
# The WatchStack keeps a stack of the modules being watched as files are
-
# loaded. If a file in the process of being loaded (parent.rb) triggers the
-
# load of another file (child.rb) the stack will ensure that child.rb
-
# handles the new constants.
-
#
-
# If child.rb is being autoloaded, its constants will be added to
-
# autoloaded_constants. If it was being `require`d, they will be discarded.
-
#
-
# This is handled by walking back up the watch stack and adding the constants
-
# found by child.rb to the list of original constants in parent.rb.
-
1
class WatchStack
-
1
include Enumerable
-
-
# @watching is a stack of lists of constants being watched. For instance,
-
# if parent.rb is autoloaded, the stack will look like [[Object]]. If
-
# parent.rb then requires namespace/child.rb, the stack will look like
-
# [[Object], [Namespace]].
-
-
1
def initialize
-
1
@watching = []
-
2
@stack = Hash.new { |h,k| h[k] = [] }
-
end
-
-
1
def each(&block)
-
@stack.each(&block)
-
end
-
-
1
def watching?
-
1641
!@watching.empty?
-
end
-
-
# Returns a list of new constants found since the last call to
-
# <tt>watch_namespaces</tt>.
-
1
def new_constants
-
751
constants = []
-
-
# Grab the list of namespaces that we're looking for new constants under
-
751
@watching.last.each do |namespace|
-
# Retrieve the constants that were present under the namespace when watch_namespaces
-
# was originally called
-
250
original_constants = @stack[namespace].last
-
-
250
mod = Inflector.constantize(namespace) if Dependencies.qualified_const_defined?(namespace)
-
250
next unless mod.is_a?(Module)
-
-
# Get a list of the constants that were added
-
250
new_constants = mod.local_constants - original_constants
-
-
# self[namespace] returns an Array of the constants that are being evaluated
-
# for that namespace. For instance, if parent.rb requires child.rb, the first
-
# element of self[Object] will be an Array of the constants that were present
-
# before parent.rb was required. The second element will be an Array of the
-
# constants that were present before child.rb was required.
-
250
@stack[namespace].each do |namespace_constants|
-
590
namespace_constants.concat(new_constants)
-
end
-
-
# Normalize the list of new constants, and add them to the list we will return
-
250
new_constants.each do |suffix|
-
4
constants << ([namespace, suffix] - ["Object"]).join("::")
-
end
-
end
-
751
constants
-
ensure
-
# A call to new_constants is always called after a call to watch_namespaces
-
751
pop_modules(@watching.pop)
-
end
-
-
# Add a set of modules to the watch stack, remembering the initial
-
# constants.
-
1
def watch_namespaces(namespaces)
-
@watching << namespaces.map do |namespace|
-
250
module_name = Dependencies.to_constant_name(namespace)
-
250
original_constants = Dependencies.qualified_const_defined?(module_name) ?
-
Inflector.constantize(module_name).local_constants : []
-
-
250
@stack[module_name] << original_constants
-
250
module_name
-
751
end
-
end
-
-
1
private
-
1
def pop_modules(modules)
-
1001
modules.each { |mod| @stack[mod].pop }
-
end
-
end
-
-
# An internal stack used to record which constants are loaded by any block.
-
1
mattr_accessor :constant_watch_stack
-
1
self.constant_watch_stack = WatchStack.new
-
-
# Module includes this module.
-
1
module ModuleConstMissing #:nodoc:
-
1
def self.append_features(base)
-
1
base.class_eval do
-
# Emulate #exclude via an ivar
-
1
return if defined?(@_const_missing) && @_const_missing
-
1
@_const_missing = instance_method(:const_missing)
-
1
remove_method(:const_missing)
-
end
-
1
super
-
end
-
-
1
def self.exclude_from(base)
-
base.class_eval do
-
define_method :const_missing, @_const_missing
-
@_const_missing = nil
-
end
-
end
-
-
1
def const_missing(const_name)
-
# The interpreter does not pass nesting information, and in the
-
# case of anonymous modules we cannot even make the trade-off of
-
# assuming their name reflects the nesting. Resort to Object as
-
# the only meaningful guess we can make.
-
573
from_mod = anonymous? ? ::Object : self
-
573
Dependencies.load_missing_constant(from_mod, const_name)
-
end
-
-
1
def unloadable(const_desc = self)
-
1
super(const_desc)
-
end
-
end
-
-
# Object includes this module.
-
1
module Loadable #:nodoc:
-
1
def self.exclude_from(base)
-
base.class_eval { define_method(:load, Kernel.instance_method(:load)) }
-
end
-
-
1
def require_or_load(file_name)
-
Dependencies.require_or_load(file_name)
-
end
-
-
1
def require_dependency(file_name, message = "No such file to load -- %s")
-
502
unless file_name.is_a?(String)
-
raise ArgumentError, "the file name must be a String -- you passed #{file_name.inspect}"
-
end
-
-
502
Dependencies.depend_on(file_name, message)
-
end
-
-
1
def load_dependency(file)
-
1641
if Dependencies.load? && ActiveSupport::Dependencies.constant_watch_stack.watching?
-
500
Dependencies.new_constants_in(Object) { yield }
-
else
-
1391
yield
-
end
-
rescue Exception => exception # errors from loading file
-
1
exception.blame_file! file
-
1
raise
-
end
-
-
1
def load(file, wrap = false)
-
2
result = false
-
4
load_dependency(file) { result = super }
-
2
result
-
end
-
-
1
def require(file)
-
1639
result = false
-
3278
load_dependency(file) { result = super }
-
1638
result
-
end
-
-
# Mark the given constant as unloadable. Unloadable constants are removed
-
# each time dependencies are cleared.
-
#
-
# Note that marking a constant for unloading need only be done once. Setup
-
# or init scripts may list each unloadable constant that may need unloading;
-
# each constant will be removed for every subsequent clear, as opposed to
-
# for the first clear.
-
#
-
# The provided constant descriptor may be a (non-anonymous) module or class,
-
# or a qualified constant name as a string or symbol.
-
#
-
# Returns +true+ if the constant was not previously marked for unloading,
-
# +false+ otherwise.
-
1
def unloadable(const_desc)
-
1
Dependencies.mark_for_unload const_desc
-
end
-
end
-
-
# Exception file-blaming.
-
1
module Blamable #:nodoc:
-
1
def blame_file!(file)
-
1
(@blamed_files ||= []).unshift file
-
end
-
-
1
def blamed_files
-
498
@blamed_files ||= []
-
end
-
-
1
def describe_blame
-
return nil if blamed_files.empty?
-
"This error occurred while loading the following files:\n #{blamed_files.join "\n "}"
-
end
-
-
1
def copy_blame!(exc)
-
498
@blamed_files = exc.blamed_files.clone
-
498
self
-
end
-
end
-
-
1
def hook!
-
2
Object.class_eval { include Loadable }
-
2
Module.class_eval { include ModuleConstMissing }
-
2
Exception.class_eval { include Blamable }
-
end
-
-
1
def unhook!
-
ModuleConstMissing.exclude_from(Module)
-
Loadable.exclude_from(Object)
-
end
-
-
1
def load?
-
2142
mechanism == :load
-
end
-
-
1
def depend_on(file_name, message = "No such file to load -- %s.rb")
-
502
path = search_for_file(file_name)
-
502
require_or_load(path || file_name)
-
rescue LoadError => load_error
-
498
if file_name = load_error.message[/ -- (.*?)(\.rb)?$/, 1]
-
498
load_error.message.replace(message % file_name)
-
498
load_error.copy_blame!(load_error)
-
end
-
498
raise
-
end
-
-
1
def clear
-
1
log_call
-
1
loaded.clear
-
1
remove_unloadable_constants!
-
end
-
-
1
def require_or_load(file_name, const_path = nil)
-
502
log_call file_name, const_path
-
502
file_name = $` if file_name =~ /\.rb\z/
-
502
expanded = File.expand_path(file_name)
-
502
return if loaded.include?(expanded)
-
-
# Record that we've seen this file *before* loading it to avoid an
-
# infinite loop with mutual dependencies.
-
501
loaded << expanded
-
-
501
begin
-
501
if load?
-
501
log "loading #{file_name}"
-
-
# Enable warnings if this file has not been loaded before and
-
# warnings_on_first_load is set.
-
501
load_args = ["#{file_name}.rb"]
-
501
load_args << const_path unless const_path.nil?
-
-
501
if !warnings_on_first_load or history.include?(expanded)
-
501
result = load_file(*load_args)
-
else
-
enable_warnings { result = load_file(*load_args) }
-
end
-
else
-
log "requiring #{file_name}"
-
result = require file_name
-
end
-
rescue Exception
-
498
loaded.delete expanded
-
498
raise
-
end
-
-
# Record history *after* loading so first load gets warnings.
-
3
history << expanded
-
3
result
-
end
-
-
# Is the provided constant path defined?
-
1
def qualified_const_defined?(path)
-
1075
Object.qualified_const_defined?(path.sub(/^::/, ''), false)
-
end
-
-
# Given +path+, a filesystem path to a ruby file, return an array of
-
# constant paths which would cause Dependencies to attempt to load this
-
# file.
-
1
def loadable_constants_for_path(path, bases = autoload_paths)
-
501
path = $` if path =~ /\.rb\z/
-
501
expanded_path = File.expand_path(path)
-
501
paths = []
-
-
501
bases.each do |root|
-
expanded_root = File.expand_path(root)
-
next unless %r{\A#{Regexp.escape(expanded_root)}(/|\\)} =~ expanded_path
-
-
nesting = expanded_path[(expanded_root.size)..-1]
-
nesting = nesting[1..-1] if nesting && nesting[0] == ?/
-
next if nesting.blank?
-
-
paths << nesting.camelize
-
end
-
-
501
paths.uniq!
-
501
paths
-
end
-
-
# Search for a file in autoload_paths matching the provided suffix.
-
1
def search_for_file(path_suffix)
-
1075
path_suffix = path_suffix.sub(/(\.rb)?$/, ".rb")
-
-
1075
autoload_paths.each do |root|
-
path = File.join(root, path_suffix)
-
return path if File.file? path
-
end
-
nil # Gee, I sure wish we had first_match ;-)
-
end
-
-
# Does the provided path_suffix correspond to an autoloadable module?
-
# Instead of returning a boolean, the autoload base for this module is
-
# returned.
-
1
def autoloadable_module?(path_suffix)
-
573
autoload_paths.each do |load_path|
-
return load_path if File.directory? File.join(load_path, path_suffix)
-
end
-
nil
-
end
-
-
1
def load_once_path?(path)
-
# to_s works around a ruby1.9 issue where #starts_with?(Pathname) will always return false
-
3
autoload_once_paths.any? { |base| path.starts_with? base.to_s }
-
end
-
-
# Attempt to autoload the provided module name by searching for a directory
-
# matching the expected path suffix. If found, the module is created and
-
# assigned to +into+'s constants with the name +const_name+. Provided that
-
# the directory was loaded from a reloadable base path, it is added to the
-
# set of constants that are to be unloaded.
-
1
def autoload_module!(into, const_name, qualified_name, path_suffix)
-
573
return nil unless base_path = autoloadable_module?(path_suffix)
-
mod = Module.new
-
into.const_set const_name, mod
-
autoloaded_constants << qualified_name unless autoload_once_paths.include?(base_path)
-
mod
-
end
-
-
# Load the file at the provided path. +const_paths+ is a set of qualified
-
# constant names. When loading the file, Dependencies will watch for the
-
# addition of these constants. Each that is defined will be marked as
-
# autoloaded, and will be removed when Dependencies.clear is next called.
-
#
-
# If the second parameter is left off, then Dependencies will construct a
-
# set of names that the file at +path+ may define. See
-
# +loadable_constants_for_path+ for more details.
-
1
def load_file(path, const_paths = loadable_constants_for_path(path))
-
501
log_call path, const_paths
-
501
const_paths = [const_paths].compact unless const_paths.is_a? Array
-
501
parent_paths = const_paths.collect { |const_path| const_path[/.*(?=::)/] || :Object }
-
-
501
result = nil
-
501
newly_defined_paths = new_constants_in(*parent_paths) do
-
501
result = Kernel.load path
-
end
-
-
3
autoloaded_constants.concat newly_defined_paths unless load_once_path?(path)
-
3
autoloaded_constants.uniq!
-
3
log "loading #{path} defined #{newly_defined_paths * ', '}" unless newly_defined_paths.empty?
-
3
result
-
end
-
-
# Returns the constant path for the provided parent and constant name.
-
1
def qualified_name_for(mod, name)
-
577
mod_name = to_constant_name mod
-
577
mod_name == "Object" ? name.to_s : "#{mod_name}::#{name}"
-
end
-
-
# Load the constant named +const_name+ which is missing from +from_mod+. If
-
# it is not possible to load the constant into from_mod, try its parent
-
# module using +const_missing+.
-
1
def load_missing_constant(from_mod, const_name)
-
573
log_call from_mod, const_name
-
-
573
unless qualified_const_defined?(from_mod.name) && Inflector.constantize(from_mod.name).equal?(from_mod)
-
raise ArgumentError, "A copy of #{from_mod} has been removed from the module tree but is still active!"
-
end
-
-
573
raise NameError, "#{from_mod} is not missing constant #{const_name}!" if from_mod.const_defined?(const_name, false)
-
-
573
qualified_name = qualified_name_for from_mod, const_name
-
573
path_suffix = qualified_name.underscore
-
-
573
file_path = search_for_file(path_suffix)
-
-
573
if file_path
-
expanded = File.expand_path(file_path)
-
expanded.sub!(/\.rb\z/, '')
-
-
if loaded.include?(expanded)
-
raise "Circular dependency detected while autoloading constant #{qualified_name}"
-
else
-
require_or_load(expanded)
-
raise LoadError, "Unable to autoload constant #{qualified_name}, expected #{file_path} to define it" unless from_mod.const_defined?(const_name, false)
-
return from_mod.const_get(const_name)
-
end
-
elsif mod = autoload_module!(from_mod, const_name, qualified_name, path_suffix)
-
return mod
-
573
elsif (parent = from_mod.parent) && parent != from_mod &&
-
532
! from_mod.parents.any? { |p| p.const_defined?(const_name, false) }
-
# If our parents do not have a constant named +const_name+ then we are free
-
# to attempt to load upwards. If they do have such a constant, then this
-
# const_missing must be due to from_mod::const_name, which should not
-
# return constants from from_mod's parents.
-
4
begin
-
# Since Ruby does not pass the nesting at the point the unknown
-
# constant triggered the callback we cannot fully emulate constant
-
# name lookup and need to make a trade-off: we are going to assume
-
# that the nesting in the body of Foo::Bar is [Foo::Bar, Foo] even
-
# though it might not be. Counterexamples are
-
#
-
# class Foo::Bar
-
# Module.nesting # => [Foo::Bar]
-
# end
-
#
-
# or
-
#
-
# module M::N
-
# module S::T
-
# Module.nesting # => [S::T, M::N]
-
# end
-
# end
-
#
-
# for example.
-
4
return parent.const_missing(const_name)
-
rescue NameError => e
-
4
raise unless e.missing_name? qualified_name_for(parent, const_name)
-
end
-
end
-
-
573
raise NameError,
-
"uninitialized constant #{qualified_name}",
-
22136
caller.reject { |l| l.starts_with? __FILE__ }
-
end
-
-
# Remove the constants that have been autoloaded, and those that have been
-
# marked for unloading. Before each constant is removed a callback is sent
-
# to its class/module if it implements +before_remove_const+.
-
#
-
# The callback implementation should be restricted to cleaning up caches, etc.
-
# as the environment will be in an inconsistent state, e.g. other constants
-
# may have already been unloaded and not accessible.
-
1
def remove_unloadable_constants!
-
2
autoloaded_constants.each { |const| remove_constant const }
-
2
autoloaded_constants.clear
-
2
Reference.clear!
-
4
explicitly_unloadable_constants.each { |const| remove_constant const }
-
end
-
-
1
class ClassCache
-
1
def initialize
-
1
@store = Hash.new
-
end
-
-
1
def empty?
-
@store.empty?
-
end
-
-
1
def key?(key)
-
@store.key?(key)
-
end
-
-
1
def get(key)
-
5404
key = key.name if key.respond_to?(:name)
-
5404
@store[key] ||= Inflector.constantize(key)
-
end
-
1
alias :[] :get
-
-
1
def safe_get(key)
-
key = key.name if key.respond_to?(:name)
-
@store[key] ||= Inflector.safe_constantize(key)
-
end
-
-
1
def store(klass)
-
return self unless klass.respond_to?(:name)
-
raise(ArgumentError, 'anonymous classes cannot be cached') if klass.name.empty?
-
@store[klass.name] = klass
-
self
-
end
-
-
1
def clear!
-
2
@store.clear
-
end
-
end
-
-
1
Reference = ClassCache.new
-
-
# Store a reference to a class +klass+.
-
1
def reference(klass)
-
Reference.store klass
-
end
-
-
# Get the reference for class named +name+.
-
# Raises an exception if referenced class does not exist.
-
1
def constantize(name)
-
5404
Reference.get(name)
-
end
-
-
# Get the reference for class named +name+ if one exists.
-
# Otherwise returns +nil+.
-
1
def safe_constantize(name)
-
Reference.safe_get(name)
-
end
-
-
# Determine if the given constant has been automatically loaded.
-
1
def autoloaded?(desc)
-
# No name => anonymous module.
-
return false if desc.is_a?(Module) && desc.anonymous?
-
name = to_constant_name desc
-
return false unless qualified_const_defined? name
-
return autoloaded_constants.include?(name)
-
end
-
-
# Will the provided constant descriptor be unloaded?
-
1
def will_unload?(const_desc)
-
autoloaded?(const_desc) ||
-
explicitly_unloadable_constants.include?(to_constant_name(const_desc))
-
end
-
-
# Mark the provided constant name for unloading. This constant will be
-
# unloaded on each request, not just the next one.
-
1
def mark_for_unload(const_desc)
-
1
name = to_constant_name const_desc
-
1
if explicitly_unloadable_constants.include? name
-
false
-
else
-
1
explicitly_unloadable_constants << name
-
1
true
-
end
-
end
-
-
# Run the provided block and detect the new constants that were loaded during
-
# its execution. Constants may only be regarded as 'new' once -- so if the
-
# block calls +new_constants_in+ again, then the constants defined within the
-
# inner call will not be reported in this one.
-
#
-
# If the provided block does not run to completion, and instead raises an
-
# exception, any new constants are regarded as being only partially defined
-
# and will be removed immediately.
-
1
def new_constants_in(*descs)
-
751
log_call(*descs)
-
-
751
constant_watch_stack.watch_namespaces(descs)
-
751
aborting = true
-
-
751
begin
-
751
yield # Now yield to the code that is to define new constants.
-
253
aborting = false
-
ensure
-
751
new_constants = constant_watch_stack.new_constants
-
-
751
log "New constants: #{new_constants * ', '}"
-
751
return new_constants unless aborting
-
-
498
log "Error during loading, removing partially loaded constants "
-
498
new_constants.each { |c| remove_constant(c) }.clear
-
end
-
-
[]
-
end
-
-
# Convert the provided const desc to a qualified constant name (as a string).
-
# A module, class, symbol, or string may be provided.
-
1
def to_constant_name(desc) #:nodoc:
-
828
case desc
-
when String then desc.sub(/^::/, '')
-
when Symbol then desc.to_s
-
when Module
-
desc.name.presence ||
-
828
raise(ArgumentError, "Anonymous modules have no name to be referenced by")
-
else raise TypeError, "Not a valid constant descriptor: #{desc.inspect}"
-
end
-
end
-
-
1
def remove_constant(const) #:nodoc:
-
2
return false unless qualified_const_defined? const
-
-
# Normalize ::Foo, Foo, Object::Foo, and ::Object::Foo to Object::Foo
-
1
names = const.to_s.sub(/^::(Object)?/, 'Object::').split("::")
-
1
to_remove = names.pop
-
1
parent = Inflector.constantize(names * '::')
-
-
1
log "removing constant #{const}"
-
1
constantized = constantize(const)
-
1
constantized.before_remove_const if constantized.respond_to?(:before_remove_const)
-
2
parent.instance_eval { remove_const to_remove }
-
-
1
true
-
end
-
-
1
protected
-
1
def log_call(*args)
-
2328
if log_activity?
-
arg_str = args.collect { |arg| arg.inspect } * ', '
-
/in `([a-z_\?\!]+)'/ =~ caller(1).first
-
selector = $1 || '<unknown>'
-
log "called #{selector}(#{arg_str})"
-
end
-
end
-
-
1
def log(msg)
-
1751
logger.debug "Dependencies: #{msg}" if log_activity?
-
end
-
-
1
def log_activity?
-
4079
logger && log_activity
-
end
-
end
-
end
-
-
1
ActiveSupport::Dependencies.hook!
-
1
require "active_support/inflector/methods"
-
-
1
module ActiveSupport
-
# Autoload and eager load conveniences for your library.
-
#
-
# This module allows you to define autoloads based on
-
# Rails conventions (i.e. no need to define the path
-
# it is automatically guessed based on the filename)
-
# and also define a set of constants that needs to be
-
# eager loaded:
-
#
-
# module MyLib
-
# extend ActiveSupport::Autoload
-
#
-
# autoload :Model
-
#
-
# eager_autoload do
-
# autoload :Cache
-
# end
-
# end
-
#
-
# Then your library can be eager loaded by simply calling:
-
#
-
# MyLib.eager_load!
-
1
module Autoload
-
1
def self.extended(base) # :nodoc:
-
12
base.class_eval do
-
12
@_autoloads = {}
-
12
@_under_path = nil
-
12
@_at_path = nil
-
12
@_eager_autoload = false
-
end
-
end
-
-
1
def autoload(const_name, path = @_at_path)
-
167
unless path
-
114
full = [name, @_under_path, const_name.to_s, path].compact.join("::")
-
114
path = Inflector.underscore(full)
-
end
-
-
167
if @_eager_autoload
-
70
@_autoloads[const_name] = path
-
end
-
-
167
super const_name, path
-
end
-
-
1
def autoload_under(path)
-
2
@_under_path, old_path = path, @_under_path
-
2
yield
-
ensure
-
2
@_under_path = old_path
-
end
-
-
1
def autoload_at(path)
-
3
@_at_path, old_path = path, @_at_path
-
3
yield
-
ensure
-
3
@_at_path = old_path
-
end
-
-
1
def eager_autoload
-
10
old_eager, @_eager_autoload = @_eager_autoload, true
-
10
yield
-
ensure
-
10
@_eager_autoload = old_eager
-
end
-
-
1
def eager_load!
-
@_autoloads.values.each { |file| require file }
-
end
-
-
1
def autoloads
-
@_autoloads
-
end
-
end
-
end
-
1
require 'singleton'
-
-
1
module ActiveSupport
-
# \Deprecation specifies the API used by Rails to deprecate methods, instance
-
# variables, objects and constants.
-
1
class Deprecation
-
# active_support.rb sets an autoload for ActiveSupport::Deprecation.
-
#
-
# If these requires were at the top of the file the constant would not be
-
# defined by the time their files were loaded. Since some of them reopen
-
# ActiveSupport::Deprecation its autoload would be triggered, resulting in
-
# a circular require warning for active_support/deprecation.rb.
-
#
-
# So, we define the constant first, and load dependencies later.
-
1
require 'active_support/deprecation/instance_delegator'
-
1
require 'active_support/deprecation/behaviors'
-
1
require 'active_support/deprecation/reporting'
-
1
require 'active_support/deprecation/method_wrappers'
-
1
require 'active_support/deprecation/proxy_wrappers'
-
1
require 'active_support/core_ext/module/deprecation'
-
-
1
include Singleton
-
1
include InstanceDelegator
-
1
include Behavior
-
1
include Reporting
-
1
include MethodWrapper
-
-
# The version the deprecated behavior will be removed, by default.
-
1
attr_accessor :deprecation_horizon
-
-
# It accepts two parameters on initialization. The first is an version of library
-
# and the second is an library name
-
#
-
# ActiveSupport::Deprecation.new('2.0', 'MyLibrary')
-
1
def initialize(deprecation_horizon = '4.1', gem_name = 'Rails')
-
1
self.gem_name = gem_name
-
1
self.deprecation_horizon = deprecation_horizon
-
# By default, warnings are not silenced and debugging is off.
-
1
self.silenced = false
-
1
self.debug = false
-
end
-
end
-
end
-
1
require "active_support/notifications"
-
-
1
module ActiveSupport
-
1
class Deprecation
-
# Default warning behaviors per Rails.env.
-
1
DEFAULT_BEHAVIORS = {
-
:stderr => Proc.new { |message, callstack|
-
$stderr.puts(message)
-
$stderr.puts callstack.join("\n ") if debug
-
},
-
:log => Proc.new { |message, callstack|
-
logger =
-
if defined?(Rails) && Rails.logger
-
Rails.logger
-
else
-
require 'active_support/logger'
-
ActiveSupport::Logger.new($stderr)
-
end
-
logger.warn message
-
logger.debug callstack.join("\n ") if debug
-
},
-
:notify => Proc.new { |message, callstack|
-
ActiveSupport::Notifications.instrument("deprecation.rails",
-
:message => message, :callstack => callstack)
-
},
-
:silence => Proc.new { |message, callstack| }
-
}
-
-
1
module Behavior
-
# Whether to print a backtrace along with the warning.
-
1
attr_accessor :debug
-
-
# Returns the current behavior or if one isn't set, defaults to +:stderr+.
-
1
def behavior
-
231
@behavior ||= [DEFAULT_BEHAVIORS[:stderr]]
-
end
-
-
# Sets the behavior to the specified value. Can be a single value, array,
-
# or an object that responds to +call+.
-
#
-
# Available behaviors:
-
#
-
# [+stderr+] Log all deprecation warnings to +$stderr+.
-
# [+log+] Log all deprecation warnings to +Rails.logger+.
-
# [+notify+] Use +ActiveSupport::Notifications+ to notify +deprecation.rails+.
-
# [+silence+] Do nothing.
-
#
-
# Setting behaviors only affects deprecations that happen after boot time.
-
# Deprecation warnings raised by gems are not affected by this setting
-
# because they happen before Rails boots up.
-
#
-
# ActiveSupport::Deprecation.behavior = :stderr
-
# ActiveSupport::Deprecation.behavior = [:stderr, :log]
-
# ActiveSupport::Deprecation.behavior = MyCustomHandler
-
# ActiveSupport::Deprecation.behavior = proc { |message, callstack|
-
# # custom stuff
-
# }
-
1
def behavior=(behavior)
-
416
@behavior = Array(behavior).map { |b| DEFAULT_BEHAVIORS[b] || b }
-
end
-
end
-
end
-
end
-
1
require 'active_support/core_ext/kernel/singleton_class'
-
1
require 'active_support/core_ext/module/delegation'
-
-
1
module ActiveSupport
-
1
class Deprecation
-
1
module InstanceDelegator
-
1
def self.included(base)
-
1
base.extend(ClassMethods)
-
1
base.public_class_method :new
-
end
-
-
1
module ClassMethods
-
1
def include(included_module)
-
15
included_module.instance_methods.each { |m| method_added(m) }
-
3
super
-
end
-
-
1
def method_added(method_name)
-
15
singleton_class.delegate(method_name, to: :instance)
-
end
-
end
-
end
-
end
-
end
-
1
require 'active_support/core_ext/module/aliasing'
-
1
require 'active_support/core_ext/array/extract_options'
-
-
1
module ActiveSupport
-
1
class Deprecation
-
1
module MethodWrapper
-
# Declare that a method has been deprecated.
-
#
-
# module Fred
-
# extend self
-
#
-
# def foo; end
-
# def bar; end
-
# def baz; end
-
# end
-
#
-
# ActiveSupport::Deprecation.deprecate_methods(Fred, :foo, bar: :qux, baz: 'use Bar#baz instead')
-
# # => [:foo, :bar, :baz]
-
#
-
# Fred.foo
-
# # => "DEPRECATION WARNING: foo is deprecated and will be removed from Rails 4.1."
-
#
-
# Fred.bar
-
# # => "DEPRECATION WARNING: bar is deprecated and will be removed from Rails 4.1 (use qux instead)."
-
#
-
# Fred.baz
-
# # => "DEPRECATION WARNING: baz is deprecated and will be removed from Rails 4.1 (use Bar#baz instead)."
-
1
def deprecate_methods(target_module, *method_names)
-
4
options = method_names.extract_options!
-
4
deprecator = options.delete(:deprecator) || ActiveSupport::Deprecation.instance
-
4
method_names += options.keys
-
-
4
method_names.each do |method_name|
-
10
target_module.alias_method_chain(method_name, :deprecation) do |target, punctuation|
-
10
target_module.send(:define_method, "#{target}_with_deprecation#{punctuation}") do |*args, &block|
-
5
deprecator.deprecation_warning(method_name, options[method_name])
-
5
send(:"#{target}_without_deprecation#{punctuation}", *args, &block)
-
end
-
end
-
end
-
end
-
end
-
end
-
end
-
1
require 'active_support/inflector/methods'
-
-
1
module ActiveSupport
-
1
class Deprecation
-
1
class DeprecationProxy #:nodoc:
-
1
def self.new(*args, &block)
-
2
object = args.first
-
-
2
return object unless object
-
2
super
-
end
-
-
98
instance_methods.each { |m| undef_method m unless m =~ /^__|^object_id$/ }
-
-
# Don't give a deprecation warning on inspect since test/unit and error
-
# logs rely on it for diagnostics.
-
1
def inspect
-
target.inspect
-
end
-
-
1
private
-
1
def method_missing(called, *args, &block)
-
warn caller, called, args
-
target.__send__(called, *args, &block)
-
end
-
end
-
-
# This DeprecatedObjectProxy transforms object to depracated object.
-
#
-
# @old_object = DeprecatedObjectProxy.new(Object.new, "Don't use this object anymore!")
-
# @old_object = DeprecatedObjectProxy.new(Object.new, "Don't use this object anymore!", deprecator_instance)
-
#
-
# When someone execute any method expect +inspect+ on proxy object this will
-
# trigger +warn+ method on +deprecator_instance+.
-
#
-
# Default deprecator is <tt>ActiveSupport::Deprecation</tt>
-
1
class DeprecatedObjectProxy < DeprecationProxy
-
1
def initialize(object, message, deprecator = ActiveSupport::Deprecation.instance)
-
@object = object
-
@message = message
-
@deprecator = deprecator
-
end
-
-
1
private
-
1
def target
-
@object
-
end
-
-
1
def warn(callstack, called, args)
-
@deprecator.warn(@message, callstack)
-
end
-
end
-
-
# This DeprecatedInstanceVariableProxy transforms instance variable to
-
# depracated instance variable.
-
#
-
# class Example
-
# def initialize(deprecator)
-
# @request = ActiveSupport::Deprecation::DeprecatedInstanceVariableProxy.new(self, :request, :@request, deprecator)
-
# @_request = :a_request
-
# end
-
#
-
# def request
-
# @_request
-
# end
-
#
-
# def old_request
-
# @request
-
# end
-
# end
-
#
-
# When someone execute any method on @request variable this will trigger
-
# +warn+ method on +deprecator_instance+ and will fetch <tt>@_request</tt>
-
# variable via +request+ method and execute the same method on non-proxy
-
# instance variable.
-
#
-
# Default deprecator is <tt>ActiveSupport::Deprecation</tt>.
-
1
class DeprecatedInstanceVariableProxy < DeprecationProxy
-
1
def initialize(instance, method, var = "@#{method}", deprecator = ActiveSupport::Deprecation.instance)
-
@instance = instance
-
@method = method
-
@var = var
-
@deprecator = deprecator
-
end
-
-
1
private
-
1
def target
-
@instance.__send__(@method)
-
end
-
-
1
def warn(callstack, called, args)
-
@deprecator.warn("#{@var} is deprecated! Call #{@method}.#{called} instead of #{@var}.#{called}. Args: #{args.inspect}", callstack)
-
end
-
end
-
-
# This DeprecatedConstantProxy transforms constant to depracated constant.
-
#
-
# OLD_CONST = ActiveSupport::Deprecation::DeprecatedConstantProxy.new('OLD_CONST', 'NEW_CONST')
-
# OLD_CONST = ActiveSupport::Deprecation::DeprecatedConstantProxy.new('OLD_CONST', 'NEW_CONST', deprecator_instance)
-
#
-
# When someone use old constant this will trigger +warn+ method on
-
# +deprecator_instance+.
-
#
-
# Default deprecator is <tt>ActiveSupport::Deprecation</tt>.
-
1
class DeprecatedConstantProxy < DeprecationProxy
-
1
def initialize(old_const, new_const, deprecator = ActiveSupport::Deprecation.instance)
-
2
@old_const = old_const
-
2
@new_const = new_const
-
2
@deprecator = deprecator
-
end
-
-
1
def class
-
target.class
-
end
-
-
1
private
-
1
def target
-
ActiveSupport::Inflector.constantize(@new_const.to_s)
-
end
-
-
1
def warn(callstack, called, args)
-
@deprecator.warn("#{@old_const} is deprecated! Use #{@new_const} instead.", callstack)
-
end
-
end
-
end
-
end
-
1
module ActiveSupport
-
1
class Deprecation
-
1
module Reporting
-
# Whether to print a message (silent mode)
-
1
attr_accessor :silenced
-
# Name of gem where method is deprecated
-
1
attr_accessor :gem_name
-
-
# Outputs a deprecation warning to the output configured by
-
# <tt>ActiveSupport::Deprecation.behavior</tt>.
-
#
-
# ActiveSupport::Deprecation.warn('something broke!')
-
# # => "DEPRECATION WARNING: something broke! (called from your_code.rb:1)"
-
1
def warn(message = nil, callstack = nil)
-
157
return if silenced
-
-
127
callstack ||= caller(2)
-
127
deprecation_message(callstack, message).tap do |m|
-
254
behavior.each { |b| b.call(m, callstack) }
-
end
-
end
-
-
# Silence deprecation warnings within the block.
-
#
-
# ActiveSupport::Deprecation.warn('something broke!')
-
# # => "DEPRECATION WARNING: something broke! (called from your_code.rb:1)"
-
#
-
# ActiveSupport::Deprecation.silence do
-
# ActiveSupport::Deprecation.warn('something broke!')
-
# end
-
# # => nil
-
1
def silence
-
16
old_silenced, @silenced = @silenced, true
-
16
yield
-
ensure
-
16
@silenced = old_silenced
-
end
-
-
1
def deprecation_warning(deprecated_method_name, message = nil, caller_backtrace = nil)
-
5
caller_backtrace ||= caller(2)
-
5
deprecated_method_warning(deprecated_method_name, message).tap do |msg|
-
5
warn(msg, caller_backtrace)
-
end
-
end
-
-
1
private
-
# Outputs a deprecation warning message
-
#
-
# ActiveSupport::Deprecation.deprecated_method_warning(:method_name)
-
# # => "method_name is deprecated and will be removed from Rails #{deprecation_horizon}"
-
# ActiveSupport::Deprecation.deprecated_method_warning(:method_name, :another_method)
-
# # => "method_name is deprecated and will be removed from Rails #{deprecation_horizon} (use another_method instead)"
-
# ActiveSupport::Deprecation.deprecated_method_warning(:method_name, "Optional message")
-
# # => "method_name is deprecated and will be removed from Rails #{deprecation_horizon} (Optional message)"
-
1
def deprecated_method_warning(method_name, message = nil)
-
5
warning = "#{method_name} is deprecated and will be removed from #{gem_name} #{deprecation_horizon}"
-
5
case message
-
5
when Symbol then "#{warning} (use #{message} instead)"
-
when String then "#{warning} (#{message})"
-
else warning
-
end
-
end
-
-
1
def deprecation_message(callstack, message = nil)
-
127
message ||= "You are using deprecated behavior which will be removed from the next major or minor release."
-
127
message += '.' unless message =~ /\.$/
-
127
"DEPRECATION WARNING: #{message} #{deprecation_caller_message(callstack)}"
-
end
-
-
1
def deprecation_caller_message(callstack)
-
127
file, line, method = extract_callstack(callstack)
-
127
if file
-
127
if line && method
-
127
"(called from #{method} at #{file}:#{line})"
-
else
-
"(called from #{file}:#{line})"
-
end
-
end
-
end
-
-
1
def extract_callstack(callstack)
-
127
rails_gem_root = File.expand_path("../../../../..", __FILE__) + "/"
-
698
offending_line = callstack.find { |line| !line.start_with?(rails_gem_root) } || callstack.first
-
127
if offending_line
-
127
if md = offending_line.match(/^(.+?):(\d+)(?::in `(.*?)')?/)
-
127
md.captures
-
else
-
offending_line
-
end
-
end
-
end
-
end
-
end
-
end
-
1
module ActiveSupport
-
# This module provides an internal implementation to track descendants
-
# which is faster than iterating through ObjectSpace.
-
1
module DescendantsTracker
-
1
@@direct_descendants = {}
-
-
1
class << self
-
1
def direct_descendants(klass)
-
@@direct_descendants[klass] || []
-
end
-
-
1
def descendants(klass)
-
7171
arr = []
-
7171
accumulate_descendants(klass, arr)
-
7171
arr
-
end
-
-
1
def clear
-
if defined? ActiveSupport::Dependencies
-
@@direct_descendants.each do |klass, descendants|
-
if ActiveSupport::Dependencies.autoloaded?(klass)
-
@@direct_descendants.delete(klass)
-
else
-
descendants.reject! { |v| ActiveSupport::Dependencies.autoloaded?(v) }
-
end
-
end
-
else
-
@@direct_descendants.clear
-
end
-
end
-
-
# This is the only method that is not thread safe, but is only ever called
-
# during the eager loading phase.
-
1
def store_inherited(klass, descendant)
-
761
(@@direct_descendants[klass] ||= []) << descendant
-
end
-
-
1
private
-
1
def accumulate_descendants(klass, acc)
-
16645
if direct_descendants = @@direct_descendants[klass]
-
4675
acc.concat(direct_descendants)
-
14149
direct_descendants.each { |direct_descendant| accumulate_descendants(direct_descendant, acc) }
-
end
-
end
-
end
-
-
1
def inherited(base)
-
761
DescendantsTracker.store_inherited(self, base)
-
761
super
-
end
-
-
1
def direct_descendants
-
DescendantsTracker.direct_descendants(self)
-
end
-
-
1
def descendants
-
4794
DescendantsTracker.descendants(self)
-
end
-
end
-
end
-
1
require 'active_support/basic_object'
-
1
require 'active_support/core_ext/array/conversions'
-
1
require 'active_support/core_ext/object/acts_like'
-
-
1
module ActiveSupport
-
# Provides accurate date and time measurements using Date#advance and
-
# Time#advance, respectively. It mainly supports the methods on Numeric.
-
#
-
# 1.month.ago # equivalent to Time.now.advance(months: -1)
-
1
class Duration < BasicObject
-
1
attr_accessor :value, :parts
-
-
1
def initialize(value, parts) #:nodoc:
-
92
@value, @parts = value, parts
-
end
-
-
# Adds another Duration or a Numeric to this Duration. Numeric values
-
# are treated as seconds.
-
1
def +(other)
-
if Duration === other
-
Duration.new(value + other.value, @parts + other.parts)
-
else
-
Duration.new(value + other, @parts + [[:seconds, other]])
-
end
-
end
-
-
# Subtracts another Duration or a Numeric from this Duration. Numeric
-
# values are treated as seconds.
-
1
def -(other)
-
self + (-other)
-
end
-
-
1
def -@ #:nodoc:
-
Duration.new(-value, parts.map { |type,number| [type, -number] })
-
end
-
-
1
def is_a?(klass) #:nodoc:
-
12
Duration == klass || value.is_a?(klass)
-
end
-
1
alias :kind_of? :is_a?
-
-
# Returns +true+ if +other+ is also a Duration instance with the
-
# same +value+, or if <tt>other == value</tt>.
-
1
def ==(other)
-
if Duration === other
-
other.value == value
-
else
-
other == value
-
end
-
end
-
-
1
def self.===(other) #:nodoc:
-
265778
other.is_a?(Duration)
-
rescue ::NoMethodError
-
false
-
end
-
-
# Calculates a new Time or Date that is as far in the future
-
# as this Duration represents.
-
1
def since(time = ::Time.current)
-
3
sum(1, time)
-
end
-
1
alias :from_now :since
-
-
# Calculates a new Time or Date that is as far in the past
-
# as this Duration represents.
-
1
def ago(time = ::Time.current)
-
32
sum(-1, time)
-
end
-
1
alias :until :ago
-
-
1
def inspect #:nodoc:
-
consolidated = parts.inject(::Hash.new(0)) { |h,(l,r)| h[l] += r; h }
-
parts = [:years, :months, :days, :minutes, :seconds].map do |length|
-
n = consolidated[length]
-
"#{n} #{n == 1 ? length.to_s.singularize : length.to_s}" if n.nonzero?
-
end.compact
-
parts = ["0 seconds"] if parts.empty?
-
parts.to_sentence(:locale => :en)
-
end
-
-
1
def as_json(options = nil) #:nodoc:
-
to_i
-
end
-
-
1
protected
-
-
1
def sum(sign, time = ::Time.current) #:nodoc:
-
35
parts.inject(time) do |t,(type,number)|
-
35
if t.acts_like?(:time) || t.acts_like?(:date)
-
35
if type == :seconds
-
4
t.since(sign * number)
-
else
-
31
t.advance(type => sign * number)
-
end
-
else
-
raise ::ArgumentError, "expected a time or date, got #{time.inspect}"
-
end
-
end
-
end
-
-
1
private
-
-
1
def method_missing(method, *args, &block) #:nodoc:
-
65
value.send(method, *args, &block)
-
end
-
end
-
end
-
1
require 'active_support/core_ext/hash/keys'
-
-
1
module ActiveSupport
-
# Implements a hash where keys <tt>:foo</tt> and <tt>"foo"</tt> are considered
-
# to be the same.
-
#
-
# rgb = ActiveSupport::HashWithIndifferentAccess.new
-
#
-
# rgb[:black] = '#000000'
-
# rgb[:black] # => '#000000'
-
# rgb['black'] # => '#000000'
-
#
-
# rgb['white'] = '#FFFFFF'
-
# rgb[:white] # => '#FFFFFF'
-
# rgb['white'] # => '#FFFFFF'
-
#
-
# Internally symbols are mapped to strings when used as keys in the entire
-
# writing interface (calling <tt>[]=</tt>, <tt>merge</tt>, etc). This
-
# mapping belongs to the public interface. For example, given:
-
#
-
# hash = ActiveSupport::HashWithIndifferentAccess.new(a: 1)
-
#
-
# You are guaranteed that the key is returned as a string:
-
#
-
# hash.keys # => ["a"]
-
#
-
# Technically other types of keys are accepted:
-
#
-
# hash = ActiveSupport::HashWithIndifferentAccess.new(a: 1)
-
# hash[0] = 0
-
# hash # => {"a"=>1, 0=>0}
-
#
-
# but this class is intended for use cases where strings or symbols are the
-
# expected keys and it is convenient to understand both as the same. For
-
# example the +params+ hash in Ruby on Rails.
-
#
-
# Note that core extensions define <tt>Hash#with_indifferent_access</tt>:
-
#
-
# rgb = { black: '#000000', white: '#FFFFFF' }.with_indifferent_access
-
#
-
# which may be handy.
-
1
class HashWithIndifferentAccess < Hash
-
# Returns +true+ so that <tt>Array#extract_options!</tt> finds members of
-
# this class.
-
1
def extractable_options?
-
true
-
end
-
-
1
def with_indifferent_access
-
13
dup
-
end
-
-
1
def nested_under_indifferent_access
-
170
self
-
end
-
-
1
def initialize(constructor = {})
-
7135
if constructor.is_a?(Hash)
-
7135
super()
-
7135
update(constructor)
-
else
-
super(constructor)
-
end
-
end
-
-
1
def default(key = nil)
-
4141
if key.is_a?(Symbol) && include?(key = key.to_s)
-
35
self[key]
-
else
-
4106
super
-
end
-
end
-
-
1
def self.new_from_hash_copying_default(hash)
-
292
new(hash).tap do |new_hash|
-
292
new_hash.default = hash.default
-
end
-
end
-
-
1
def self.[](*args)
-
3157
new.merge(Hash[*args])
-
end
-
-
1
alias_method :regular_writer, :[]= unless method_defined?(:regular_writer)
-
1
alias_method :regular_update, :update unless method_defined?(:regular_update)
-
-
# Assigns a new value to the hash:
-
#
-
# hash = ActiveSupport::HashWithIndifferentAccess.new
-
# hash[:key] = 'value'
-
#
-
# This value can be later fetched using either +:key+ or +'key'+.
-
1
def []=(key, value)
-
144
regular_writer(convert_key(key), convert_value(value))
-
end
-
-
1
alias_method :store, :[]=
-
-
# Updates the receiver in-place, merging in the hash passed as argument:
-
#
-
# hash_1 = ActiveSupport::HashWithIndifferentAccess.new
-
# hash_1[:key] = 'value'
-
#
-
# hash_2 = ActiveSupport::HashWithIndifferentAccess.new
-
# hash_2[:key] = 'New Value!'
-
#
-
# hash_1.update(hash_2) # => {"key"=>"New Value!"}
-
#
-
# The argument can be either an
-
# <tt>ActiveSupport::HashWithIndifferentAccess</tt> or a regular +Hash+.
-
# In either case the merge respects the semantics of indifferent access.
-
#
-
# If the argument is a regular hash with keys +:key+ and +"key"+ only one
-
# of the values end up in the receiver, but which one is unspecified.
-
#
-
# When given a block, the value for duplicated keys will be determined
-
# by the result of invoking the block with the duplicated key, the value
-
# in the receiver, and the value in +other_hash+. The rules for duplicated
-
# keys follow the semantics of indifferent access:
-
#
-
# hash_1[:key] = 10
-
# hash_2['key'] = 12
-
# hash_1.update(hash_2) { |key, old, new| old + new } # => {"key"=>22}
-
1
def update(other_hash)
-
10292
if other_hash.is_a? HashWithIndifferentAccess
-
3549
super(other_hash)
-
else
-
6743
other_hash.each_pair do |key, value|
-
8946
if block_given? && key?(key)
-
value = yield(convert_key(key), self[key], value)
-
end
-
8946
regular_writer(convert_key(key), convert_value(value))
-
end
-
6743
self
-
end
-
end
-
-
1
alias_method :merge!, :update
-
-
# Checks the hash for a key matching the argument passed in:
-
#
-
# hash = ActiveSupport::HashWithIndifferentAccess.new
-
# hash['key'] = 'value'
-
# hash.key?(:key) # => true
-
# hash.key?('key') # => true
-
1
def key?(key)
-
141
super(convert_key(key))
-
end
-
-
1
alias_method :include?, :key?
-
1
alias_method :has_key?, :key?
-
1
alias_method :member?, :key?
-
-
# Same as <tt>Hash#fetch</tt> where the key passed as argument can be
-
# either a string or a symbol:
-
#
-
# counters = ActiveSupport::HashWithIndifferentAccess.new
-
# counters[:foo] = 1
-
#
-
# counters.fetch('foo') # => 1
-
# counters.fetch(:bar, 0) # => 0
-
# counters.fetch(:bar) {|key| 0} # => 0
-
# counters.fetch(:zoo) # => KeyError: key not found: "zoo"
-
1
def fetch(key, *extras)
-
super(convert_key(key), *extras)
-
end
-
-
# Returns an array of the values at the specified indices:
-
#
-
# hash = ActiveSupport::HashWithIndifferentAccess.new
-
# hash[:a] = 'x'
-
# hash[:b] = 'y'
-
# hash.values_at('a', 'b') # => ["x", "y"]
-
1
def values_at(*indices)
-
indices.collect {|key| self[convert_key(key)]}
-
end
-
-
# Returns an exact copy of the hash.
-
1
def dup
-
3549
self.class.new(self).tap do |new_hash|
-
3549
new_hash.default = default
-
end
-
end
-
-
# This method has the same semantics of +update+, except it does not
-
# modify the receiver but rather returns a new hash with indifferent
-
# access with the result of the merge.
-
1
def merge(hash, &block)
-
3157
self.dup.update(hash, &block)
-
end
-
-
# Like +merge+ but the other way around: Merges the receiver into the
-
# argument and returns a new hash with indifferent access as result:
-
#
-
# hash = ActiveSupport::HashWithIndifferentAccess.new
-
# hash['a'] = nil
-
# hash.reverse_merge(a: 0, b: 1) # => {"a"=>nil, "b"=>1}
-
1
def reverse_merge(other_hash)
-
super(self.class.new_from_hash_copying_default(other_hash))
-
end
-
-
# Same semantics as +reverse_merge+ but modifies the receiver in-place.
-
1
def reverse_merge!(other_hash)
-
replace(reverse_merge( other_hash ))
-
end
-
-
# Replaces the contents of this hash with other_hash.
-
#
-
# h = { "a" => 100, "b" => 200 }
-
# h.replace({ "c" => 300, "d" => 400 }) #=> {"c"=>300, "d"=>400}
-
1
def replace(other_hash)
-
super(self.class.new_from_hash_copying_default(other_hash))
-
end
-
-
# Removes the specified key from the hash.
-
1
def delete(key)
-
420
super(convert_key(key))
-
end
-
-
1
def stringify_keys!; self end
-
1
def deep_stringify_keys!; self end
-
171
def stringify_keys; dup end
-
1
def deep_stringify_keys; dup end
-
1
undef :symbolize_keys!
-
1
undef :deep_symbolize_keys!
-
1
def symbolize_keys; to_hash.symbolize_keys end
-
1
def deep_symbolize_keys; to_hash.deep_symbolize_keys end
-
1
def to_options!; self end
-
-
# Convert to a regular hash with string keys.
-
1
def to_hash
-
Hash.new(default).merge!(self)
-
end
-
-
1
protected
-
1
def convert_key(key)
-
9651
key.kind_of?(Symbol) ? key.to_s : key
-
end
-
-
1
def convert_value(value)
-
26085
if value.is_a? Hash
-
199
value.nested_under_indifferent_access
-
25886
elsif value.is_a?(Array)
-
8507
value = value.dup if value.frozen?
-
25502
value.map! { |e| convert_value(e) }
-
else
-
17379
value
-
end
-
end
-
end
-
end
-
-
1
HashWithIndifferentAccess = ActiveSupport::HashWithIndifferentAccess
-
1
begin
-
1
require 'i18n'
-
1
require 'active_support/lazy_load_hooks'
-
rescue LoadError => e
-
$stderr.puts "The i18n gem is not available. Please add it to your Gemfile and run bundle install"
-
raise e
-
end
-
-
1
ActiveSupport.run_load_hooks(:i18n)
-
1
I18n.load_path << "#{File.dirname(__FILE__)}/locale/en.yml"
-
1
require 'active_support/inflector/inflections'
-
-
1
module ActiveSupport
-
1
Inflector.inflections(:en) do |inflect|
-
1
inflect.plural(/$/, 's')
-
1
inflect.plural(/s$/i, 's')
-
1
inflect.plural(/^(ax|test)is$/i, '\1es')
-
1
inflect.plural(/(octop|vir)us$/i, '\1i')
-
1
inflect.plural(/(octop|vir)i$/i, '\1i')
-
1
inflect.plural(/(alias|status)$/i, '\1es')
-
1
inflect.plural(/(bu)s$/i, '\1ses')
-
1
inflect.plural(/(buffal|tomat)o$/i, '\1oes')
-
1
inflect.plural(/([ti])um$/i, '\1a')
-
1
inflect.plural(/([ti])a$/i, '\1a')
-
1
inflect.plural(/sis$/i, 'ses')
-
1
inflect.plural(/(?:([^f])fe|([lr])f)$/i, '\1\2ves')
-
1
inflect.plural(/(hive)$/i, '\1s')
-
1
inflect.plural(/([^aeiouy]|qu)y$/i, '\1ies')
-
1
inflect.plural(/(x|ch|ss|sh)$/i, '\1es')
-
1
inflect.plural(/(matr|vert|ind)(?:ix|ex)$/i, '\1ices')
-
1
inflect.plural(/^(m|l)ouse$/i, '\1ice')
-
1
inflect.plural(/^(m|l)ice$/i, '\1ice')
-
1
inflect.plural(/^(ox)$/i, '\1en')
-
1
inflect.plural(/^(oxen)$/i, '\1')
-
1
inflect.plural(/(quiz)$/i, '\1zes')
-
-
1
inflect.singular(/s$/i, '')
-
1
inflect.singular(/(ss)$/i, '\1')
-
1
inflect.singular(/(n)ews$/i, '\1ews')
-
1
inflect.singular(/([ti])a$/i, '\1um')
-
1
inflect.singular(/((a)naly|(b)a|(d)iagno|(p)arenthe|(p)rogno|(s)ynop|(t)he)(sis|ses)$/i, '\1sis')
-
1
inflect.singular(/(^analy)(sis|ses)$/i, '\1sis')
-
1
inflect.singular(/([^f])ves$/i, '\1fe')
-
1
inflect.singular(/(hive)s$/i, '\1')
-
1
inflect.singular(/(tive)s$/i, '\1')
-
1
inflect.singular(/([lr])ves$/i, '\1f')
-
1
inflect.singular(/([^aeiouy]|qu)ies$/i, '\1y')
-
1
inflect.singular(/(s)eries$/i, '\1eries')
-
1
inflect.singular(/(m)ovies$/i, '\1ovie')
-
1
inflect.singular(/(x|ch|ss|sh)es$/i, '\1')
-
1
inflect.singular(/^(m|l)ice$/i, '\1ouse')
-
1
inflect.singular(/(bus)(es)?$/i, '\1')
-
1
inflect.singular(/(o)es$/i, '\1')
-
1
inflect.singular(/(shoe)s$/i, '\1')
-
1
inflect.singular(/(cris|test)(is|es)$/i, '\1is')
-
1
inflect.singular(/^(a)x[ie]s$/i, '\1xis')
-
1
inflect.singular(/(octop|vir)(us|i)$/i, '\1us')
-
1
inflect.singular(/(alias|status)(es)?$/i, '\1')
-
1
inflect.singular(/^(ox)en/i, '\1')
-
1
inflect.singular(/(vert|ind)ices$/i, '\1ex')
-
1
inflect.singular(/(matr)ices$/i, '\1ix')
-
1
inflect.singular(/(quiz)zes$/i, '\1')
-
1
inflect.singular(/(database)s$/i, '\1')
-
-
1
inflect.irregular('person', 'people')
-
1
inflect.irregular('man', 'men')
-
1
inflect.irregular('child', 'children')
-
1
inflect.irregular('sex', 'sexes')
-
1
inflect.irregular('move', 'moves')
-
1
inflect.irregular('cow', 'kine')
-
1
inflect.irregular('zombie', 'zombies')
-
-
1
inflect.uncountable(%w(equipment information rice money species series fish sheep jeans police))
-
end
-
end
-
# in case active_support/inflector is required without the rest of active_support
-
1
require 'active_support/inflector/inflections'
-
1
require 'active_support/inflector/transliterate'
-
1
require 'active_support/inflector/methods'
-
-
1
require 'active_support/inflections'
-
1
require 'active_support/core_ext/string/inflections'
-
1
require 'active_support/core_ext/array/prepend_and_append'
-
1
require 'active_support/i18n'
-
-
1
module ActiveSupport
-
1
module Inflector
-
1
extend self
-
-
# A singleton instance of this class is yielded by Inflector.inflections,
-
# which can then be used to specify additional inflection rules. If passed
-
# an optional locale, rules for other languages can be specified. The
-
# default locale is <tt>:en</tt>. Only rules for English are provided.
-
#
-
# ActiveSupport::Inflector.inflections(:en) do |inflect|
-
# inflect.plural /^(ox)$/i, '\1\2en'
-
# inflect.singular /^(ox)en/i, '\1'
-
#
-
# inflect.irregular 'octopus', 'octopi'
-
#
-
# inflect.uncountable 'equipment'
-
# end
-
#
-
# New rules are added at the top. So in the example above, the irregular
-
# rule for octopus will now be the first of the pluralization and
-
# singularization rules that is runs. This guarantees that your rules run
-
# before any of the rules that may already have been loaded.
-
1
class Inflections
-
1
def self.instance(locale = :en)
-
11888
@__instance__ ||= Hash.new { |h, k| h[k] = new }
-
11887
@__instance__[locale]
-
end
-
-
1
attr_reader :plurals, :singulars, :uncountables, :humans, :acronyms, :acronym_regex
-
-
1
def initialize
-
1
@plurals, @singulars, @uncountables, @humans, @acronyms, @acronym_regex = [], [], [], [], {}, /(?=a)b/
-
end
-
-
# Private, for the test suite.
-
1
def initialize_dup(orig) # :nodoc:
-
%w(plurals singulars uncountables humans acronyms acronym_regex).each do |scope|
-
instance_variable_set("@#{scope}", orig.send(scope).dup)
-
end
-
end
-
-
# Specifies a new acronym. An acronym must be specified as it will appear
-
# in a camelized string. An underscore string that contains the acronym
-
# will retain the acronym when passed to +camelize+, +humanize+, or
-
# +titleize+. A camelized string that contains the acronym will maintain
-
# the acronym when titleized or humanized, and will convert the acronym
-
# into a non-delimited single lowercase word when passed to +underscore+.
-
#
-
# acronym 'HTML'
-
# titleize 'html' #=> 'HTML'
-
# camelize 'html' #=> 'HTML'
-
# underscore 'MyHTML' #=> 'my_html'
-
#
-
# The acronym, however, must occur as a delimited unit and not be part of
-
# another word for conversions to recognize it:
-
#
-
# acronym 'HTTP'
-
# camelize 'my_http_delimited' #=> 'MyHTTPDelimited'
-
# camelize 'https' #=> 'Https', not 'HTTPs'
-
# underscore 'HTTPS' #=> 'http_s', not 'https'
-
#
-
# acronym 'HTTPS'
-
# camelize 'https' #=> 'HTTPS'
-
# underscore 'HTTPS' #=> 'https'
-
#
-
# Note: Acronyms that are passed to +pluralize+ will no longer be
-
# recognized, since the acronym will not occur as a delimited unit in the
-
# pluralized result. To work around this, you must specify the pluralized
-
# form as an acronym as well:
-
#
-
# acronym 'API'
-
# camelize(pluralize('api')) #=> 'Apis'
-
#
-
# acronym 'APIs'
-
# camelize(pluralize('api')) #=> 'APIs'
-
#
-
# +acronym+ may be used to specify any word that contains an acronym or
-
# otherwise needs to maintain a non-standard capitalization. The only
-
# restriction is that the word must begin with a capital letter.
-
#
-
# acronym 'RESTful'
-
# underscore 'RESTful' #=> 'restful'
-
# underscore 'RESTfulController' #=> 'restful_controller'
-
# titleize 'RESTfulController' #=> 'RESTful Controller'
-
# camelize 'restful' #=> 'RESTful'
-
# camelize 'restful_controller' #=> 'RESTfulController'
-
#
-
# acronym 'McDonald'
-
# underscore 'McDonald' #=> 'mcdonald'
-
# camelize 'mcdonald' #=> 'McDonald'
-
1
def acronym(word)
-
@acronyms[word.downcase] = word
-
@acronym_regex = /#{@acronyms.values.join("|")}/
-
end
-
-
# Specifies a new pluralization rule and its replacement. The rule can
-
# either be a string or a regular expression. The replacement should
-
# always be a string that may include references to the matched data from
-
# the rule.
-
1
def plural(rule, replacement)
-
37
@uncountables.delete(rule) if rule.is_a?(String)
-
37
@uncountables.delete(replacement)
-
37
@plurals.prepend([rule, replacement])
-
end
-
-
# Specifies a new singularization rule and its replacement. The rule can
-
# either be a string or a regular expression. The replacement should
-
# always be a string that may include references to the matched data from
-
# the rule.
-
1
def singular(rule, replacement)
-
35
@uncountables.delete(rule) if rule.is_a?(String)
-
35
@uncountables.delete(replacement)
-
35
@singulars.prepend([rule, replacement])
-
end
-
-
# Specifies a new irregular that applies to both pluralization and
-
# singularization at the same time. This can only be used for strings, not
-
# regular expressions. You simply pass the irregular in singular and
-
# plural form.
-
#
-
# irregular 'octopus', 'octopi'
-
# irregular 'person', 'people'
-
1
def irregular(singular, plural)
-
7
@uncountables.delete(singular)
-
7
@uncountables.delete(plural)
-
7
if singular[0,1].upcase == plural[0,1].upcase
-
6
plural(Regexp.new("(#{singular[0,1]})#{singular[1..-1]}$", "i"), '\1' + plural[1..-1])
-
6
plural(Regexp.new("(#{plural[0,1]})#{plural[1..-1]}$", "i"), '\1' + plural[1..-1])
-
6
singular(Regexp.new("(#{plural[0,1]})#{plural[1..-1]}$", "i"), '\1' + singular[1..-1])
-
else
-
1
plural(Regexp.new("#{singular[0,1].upcase}(?i)#{singular[1..-1]}$"), plural[0,1].upcase + plural[1..-1])
-
1
plural(Regexp.new("#{singular[0,1].downcase}(?i)#{singular[1..-1]}$"), plural[0,1].downcase + plural[1..-1])
-
1
plural(Regexp.new("#{plural[0,1].upcase}(?i)#{plural[1..-1]}$"), plural[0,1].upcase + plural[1..-1])
-
1
plural(Regexp.new("#{plural[0,1].downcase}(?i)#{plural[1..-1]}$"), plural[0,1].downcase + plural[1..-1])
-
1
singular(Regexp.new("#{plural[0,1].upcase}(?i)#{plural[1..-1]}$"), singular[0,1].upcase + singular[1..-1])
-
1
singular(Regexp.new("#{plural[0,1].downcase}(?i)#{plural[1..-1]}$"), singular[0,1].downcase + singular[1..-1])
-
end
-
end
-
-
# Add uncountable words that shouldn't be attempted inflected.
-
#
-
# uncountable 'money'
-
# uncountable 'money', 'information'
-
# uncountable %w( money information rice )
-
1
def uncountable(*words)
-
1
(@uncountables << words).flatten!
-
end
-
-
# Specifies a humanized form of a string by a regular expression rule or
-
# by a string mapping. When using a regular expression based replacement,
-
# the normal humanize formatting is called after the replacement. When a
-
# string is used, the human form should be specified as desired (example:
-
# 'The name', not 'the_name').
-
#
-
# human /_cnt$/i, '\1_count'
-
# human 'legacy_col_person_name', 'Name'
-
1
def human(rule, replacement)
-
@humans.prepend([rule, replacement])
-
end
-
-
# Clears the loaded inflections within a given scope (default is
-
# <tt>:all</tt>). Give the scope as a symbol of the inflection type, the
-
# options are: <tt>:plurals</tt>, <tt>:singulars</tt>, <tt>:uncountables</tt>,
-
# <tt>:humans</tt>.
-
#
-
# clear :all
-
# clear :plurals
-
1
def clear(scope = :all)
-
case scope
-
when :all
-
@plurals, @singulars, @uncountables, @humans = [], [], [], []
-
else
-
instance_variable_set "@#{scope}", []
-
end
-
end
-
end
-
-
# Yields a singleton instance of Inflector::Inflections so you can specify
-
# additional inflector rules. If passed an optional locale, rules for other
-
# languages can be specified. If not specified, defaults to <tt>:en</tt>.
-
# Only rules for English are provided.
-
#
-
# ActiveSupport::Inflector.inflections(:en) do |inflect|
-
# inflect.uncountable 'rails'
-
# end
-
1
def inflections(locale = :en)
-
11887
if block_given?
-
1
yield Inflections.instance(locale)
-
else
-
11886
Inflections.instance(locale)
-
end
-
end
-
end
-
end
-
# encoding: utf-8
-
-
1
require 'active_support/inflector/inflections'
-
1
require 'active_support/inflections'
-
-
1
module ActiveSupport
-
# The Inflector transforms words from singular to plural, class names to table
-
# names, modularized class names to ones without, and class names to foreign
-
# keys. The default inflections for pluralization, singularization, and
-
# uncountable words are kept in inflections.rb.
-
#
-
# The Rails core team has stated patches for the inflections library will not
-
# be accepted in order to avoid breaking legacy applications which may be
-
# relying on errant inflections. If you discover an incorrect inflection and
-
# require it for your application or wish to define rules for languages other
-
# than English, please correct or add them yourself (explained below).
-
1
module Inflector
-
1
extend self
-
-
# Returns the plural form of the word in the string.
-
#
-
# If passed an optional +locale+ parameter, the word will be
-
# pluralized using rules defined for that language. By default,
-
# this parameter is set to <tt>:en</tt>.
-
#
-
# 'post'.pluralize # => "posts"
-
# 'octopus'.pluralize # => "octopi"
-
# 'sheep'.pluralize # => "sheep"
-
# 'words'.pluralize # => "words"
-
# 'CamelOctopus'.pluralize # => "CamelOctopi"
-
# 'ley'.pluralize(:es) # => "leyes"
-
1
def pluralize(word, locale = :en)
-
1073
apply_inflections(word, inflections(locale).plurals)
-
end
-
-
# The reverse of +pluralize+, returns the singular form of a word in a
-
# string.
-
#
-
# If passed an optional +locale+ parameter, the word will be
-
# pluralized using rules defined for that language. By default,
-
# this parameter is set to <tt>:en</tt>.
-
#
-
# 'posts'.singularize # => "post"
-
# 'octopi'.singularize # => "octopus"
-
# 'sheep'.singularize # => "sheep"
-
# 'word'.singularize # => "word"
-
# 'CamelOctopi'.singularize # => "CamelOctopus"
-
# 'leyes'.singularize(:es) # => "ley"
-
1
def singularize(word, locale = :en)
-
2636
apply_inflections(word, inflections(locale).singulars)
-
end
-
-
# By default, +camelize+ converts strings to UpperCamelCase. If the argument
-
# to +camelize+ is set to <tt>:lower</tt> then +camelize+ produces
-
# lowerCamelCase.
-
#
-
# +camelize+ will also convert '/' to '::' which is useful for converting
-
# paths to namespaces.
-
#
-
# 'active_model'.camelize # => "ActiveModel"
-
# 'active_model'.camelize(:lower) # => "activeModel"
-
# 'active_model/errors'.camelize # => "ActiveModel::Errors"
-
# 'active_model/errors'.camelize(:lower) # => "activeModel::Errors"
-
#
-
# As a rule of thumb you can think of +camelize+ as the inverse of
-
# +underscore+, though there are cases where that does not hold:
-
#
-
# 'SSLError'.underscore.camelize # => "SslError"
-
1
def camelize(term, uppercase_first_letter = true)
-
1172
string = term.to_s
-
1172
if uppercase_first_letter
-
2344
string = string.sub(/^[a-z\d]*/) { inflections.acronyms[$&] || $&.capitalize }
-
else
-
string = string.sub(/^(?:#{inflections.acronym_regex}(?=\b|[A-Z_])|\w)/) { $&.downcase }
-
end
-
1686
string.gsub(/(?:_|(\/))([a-z\d]*)/i) { "#{$1}#{inflections.acronyms[$2] || $2.capitalize}" }.gsub('/', '::')
-
end
-
-
# Makes an underscored, lowercase form from the expression in the string.
-
#
-
# Changes '::' to '/' to convert namespaces to paths.
-
#
-
# 'ActiveModel'.underscore # => "active_model"
-
# 'ActiveModel::Errors'.underscore # => "active_model/errors"
-
#
-
# As a rule of thumb you can think of +underscore+ as the inverse of
-
# +camelize+, though there are cases where that does not hold:
-
#
-
# 'SSLError'.underscore.camelize # => "SslError"
-
1
def underscore(camel_cased_word)
-
1532
word = camel_cased_word.to_s.dup
-
1532
word.gsub!('::', '/')
-
1532
word.gsub!(/(?:([A-Za-z\d])|^)(#{inflections.acronym_regex})(?=\b|[^a-z])/) { "#{$1}#{$1 && '_'}#{$2.downcase}" }
-
1532
word.gsub!(/([A-Z\d]+)([A-Z][a-z])/,'\1_\2')
-
1532
word.gsub!(/([a-z\d])([A-Z])/,'\1_\2')
-
1532
word.tr!("-", "_")
-
1532
word.downcase!
-
1532
word
-
end
-
-
# Capitalizes the first word and turns underscores into spaces and strips a
-
# trailing "_id", if any. Like +titleize+, this is meant for creating pretty
-
# output.
-
#
-
# 'employee_salary'.humanize # => "Employee salary"
-
# 'author_id'.humanize # => "Author"
-
1
def humanize(lower_case_and_underscored_word)
-
380
result = lower_case_and_underscored_word.to_s.dup
-
380
inflections.humans.each { |(rule, replacement)| break if result.sub!(rule, replacement) }
-
380
result.gsub!(/_id$/, "")
-
380
result.tr!('_', ' ')
-
380
result.gsub(/([a-z\d]*)/i) { |match|
-
872
"#{inflections.acronyms[match] || match.downcase}"
-
380
}.gsub(/^\w/) { $&.upcase }
-
end
-
-
# Capitalizes all the words and replaces some characters in the string to
-
# create a nicer looking title. +titleize+ is meant for creating pretty
-
# output. It is not used in the Rails internals.
-
#
-
# +titleize+ is also aliased as +titlecase+.
-
#
-
# 'man from the boondocks'.titleize # => "Man From The Boondocks"
-
# 'x-men: the last stand'.titleize # => "X Men: The Last Stand"
-
# 'TheManWithoutAPast'.titleize # => "The Man Without A Past"
-
# 'raiders_of_the_lost_ark'.titleize # => "Raiders Of The Lost Ark"
-
1
def titleize(word)
-
2
humanize(underscore(word)).gsub(/\b(?<!['’`])[a-z]/) { $&.capitalize }
-
end
-
-
# Create the name of a table like Rails does for models to table names. This
-
# method uses the +pluralize+ method on the last word in the string.
-
#
-
# 'RawScaledScorer'.tableize # => "raw_scaled_scorers"
-
# 'egg_and_ham'.tableize # => "egg_and_hams"
-
# 'fancyCategory'.tableize # => "fancy_categories"
-
1
def tableize(class_name)
-
38
pluralize(underscore(class_name))
-
end
-
-
# Create a class name from a plural table name like Rails does for table
-
# names to models. Note that this returns a string and not a Class (To
-
# convert to an actual class follow +classify+ with +constantize+).
-
#
-
# 'egg_and_hams'.classify # => "EggAndHam"
-
# 'posts'.classify # => "Post"
-
#
-
# Singular names are not handled correctly:
-
#
-
# 'business'.classify # => "Busines"
-
1
def classify(table_name)
-
# strip out any leading schema name
-
11
camelize(singularize(table_name.to_s.sub(/.*\./, '')))
-
end
-
-
# Replaces underscores with dashes in the string.
-
#
-
# 'puni_puni'.dasherize # => "puni-puni"
-
1
def dasherize(underscored_word)
-
1
underscored_word.tr('_', '-')
-
end
-
-
# Removes the module part from the expression in the string.
-
#
-
# 'ActiveRecord::CoreExtensions::String::Inflections'.demodulize # => "Inflections"
-
# 'Inflections'.demodulize # => "Inflections"
-
#
-
# See also +deconstantize+.
-
1
def demodulize(path)
-
668
path = path.to_s
-
668
if i = path.rindex('::')
-
161
path[(i+2)..-1]
-
else
-
507
path
-
end
-
end
-
-
# Removes the rightmost segment from the constant expression in the string.
-
#
-
# 'Net::HTTP'.deconstantize # => "Net"
-
# '::Net::HTTP'.deconstantize # => "::Net"
-
# 'String'.deconstantize # => ""
-
# '::String'.deconstantize # => ""
-
# ''.deconstantize # => ""
-
#
-
# See also +demodulize+.
-
1
def deconstantize(path)
-
path.to_s[0...(path.rindex('::') || 0)] # implementation based on the one in facets' Module#spacename
-
end
-
-
# Creates a foreign key name from a class name.
-
# +separate_class_name_and_id_with_underscore+ sets whether
-
# the method should put '_' between the name and 'id'.
-
#
-
# 'Message'.foreign_key # => "message_id"
-
# 'Message'.foreign_key(false) # => "messageid"
-
# 'Admin::Post'.foreign_key # => "post_id"
-
1
def foreign_key(class_name, separate_class_name_and_id_with_underscore = true)
-
223
underscore(demodulize(class_name)) + (separate_class_name_and_id_with_underscore ? "_id" : "id")
-
end
-
-
# Tries to find a constant with the name specified in the argument string.
-
#
-
# 'Module'.constantize # => Module
-
# 'Test::Unit'.constantize # => Test::Unit
-
#
-
# The name is assumed to be the one of a top-level constant, no matter
-
# whether it starts with "::" or not. No lexical context is taken into
-
# account:
-
#
-
# C = 'outside'
-
# module M
-
# C = 'inside'
-
# C # => 'inside'
-
# 'C'.constantize # => 'outside', same as ::C
-
# end
-
#
-
# NameError is raised when the name is not in CamelCase or the constant is
-
# unknown.
-
1
def constantize(camel_cased_word)
-
5229
names = camel_cased_word.split('::')
-
5229
names.shift if names.empty? || names.first.empty?
-
-
5229
names.inject(Object) do |constant, name|
-
6326
if constant == Object
-
5228
constant.const_get(name)
-
else
-
1098
candidate = constant.const_get(name)
-
1071
next candidate if constant.const_defined?(name, false)
-
480
next candidate unless Object.const_defined?(name)
-
-
# Go down the ancestors to check it it's owned
-
# directly before we reach Object or the end of ancestors.
-
480
constant = constant.ancestors.inject do |const, ancestor|
-
24976
break const if ancestor == Object
-
24509
break ancestor if ancestor.const_defined?(name, false)
-
24509
const
-
end
-
-
# owner is in Object, so raise
-
480
constant.const_get(name, false)
-
end
-
end
-
end
-
-
# Tries to find a constant with the name specified in the argument string.
-
#
-
# 'Module'.safe_constantize # => Module
-
# 'Test::Unit'.safe_constantize # => Test::Unit
-
#
-
# The name is assumed to be the one of a top-level constant, no matter
-
# whether it starts with "::" or not. No lexical context is taken into
-
# account:
-
#
-
# C = 'outside'
-
# module M
-
# C = 'inside'
-
# C # => 'inside'
-
# 'C'.safe_constantize # => 'outside', same as ::C
-
# end
-
#
-
# +nil+ is returned when the name is not in CamelCase or the constant (or
-
# part of it) is unknown.
-
#
-
# 'blargle'.safe_constantize # => nil
-
# 'UnknownModule'.safe_constantize # => nil
-
# 'UnknownModule::Foo::Bar'.safe_constantize # => nil
-
1
def safe_constantize(camel_cased_word)
-
16
begin
-
16
constantize(camel_cased_word)
-
3
rescue NameError => e
-
raise unless e.message =~ /(uninitialized constant|wrong constant name) #{const_regexp(camel_cased_word)}$/ ||
-
3
e.name.to_s == camel_cased_word.to_s
-
rescue ArgumentError => e
-
raise unless e.message =~ /not missing constant #{const_regexp(camel_cased_word)}\!$/
-
end
-
end
-
-
# Returns the suffix that should be added to a number to denote the position
-
# in an ordered sequence such as 1st, 2nd, 3rd, 4th.
-
#
-
# ordinal(1) # => "st"
-
# ordinal(2) # => "nd"
-
# ordinal(1002) # => "nd"
-
# ordinal(1003) # => "rd"
-
# ordinal(-11) # => "th"
-
# ordinal(-1021) # => "st"
-
1
def ordinal(number)
-
abs_number = number.to_i.abs
-
-
if (11..13).include?(abs_number % 100)
-
"th"
-
else
-
case abs_number % 10
-
when 1; "st"
-
when 2; "nd"
-
when 3; "rd"
-
else "th"
-
end
-
end
-
end
-
-
# Turns a number into an ordinal string used to denote the position in an
-
# ordered sequence such as 1st, 2nd, 3rd, 4th.
-
#
-
# ordinalize(1) # => "1st"
-
# ordinalize(2) # => "2nd"
-
# ordinalize(1002) # => "1002nd"
-
# ordinalize(1003) # => "1003rd"
-
# ordinalize(-11) # => "-11th"
-
# ordinalize(-1021) # => "-1021st"
-
1
def ordinalize(number)
-
"#{number}#{ordinal(number)}"
-
end
-
-
1
private
-
-
# Mount a regular expression that will match part by part of the constant.
-
# For instance, Foo::Bar::Baz will generate Foo(::Bar(::Baz)?)?
-
1
def const_regexp(camel_cased_word) #:nodoc:
-
3
parts = camel_cased_word.split("::")
-
3
last = parts.pop
-
-
3
parts.reverse.inject(last) do |acc, part|
-
part.empty? ? acc : "#{part}(::#{acc})?"
-
end
-
end
-
-
# Applies inflection rules for +singularize+ and +pluralize+.
-
#
-
# apply_inflections('post', inflections.plurals) # => "posts"
-
# apply_inflections('posts', inflections.singulars) # => "post"
-
1
def apply_inflections(word, rules)
-
3709
result = word.to_s.dup
-
-
3709
if word.empty? || inflections.uncountables.include?(result.downcase[/\b\w+\Z/])
-
2
result
-
else
-
127726
rules.each { |(rule, replacement)| break if result.sub!(rule, replacement) }
-
3707
result
-
end
-
end
-
end
-
end
-
# encoding: utf-8
-
1
require 'active_support/core_ext/string/multibyte'
-
1
require 'active_support/i18n'
-
-
1
module ActiveSupport
-
1
module Inflector
-
-
# Replaces non-ASCII characters with an ASCII approximation, or if none
-
# exists, a replacement character which defaults to "?".
-
#
-
# transliterate('Ærøskøbing')
-
# # => "AEroskobing"
-
#
-
# Default approximations are provided for Western/Latin characters,
-
# e.g, "ø", "ñ", "é", "ß", etc.
-
#
-
# This method is I18n aware, so you can set up custom approximations for a
-
# locale. This can be useful, for example, to transliterate German's "ü"
-
# and "ö" to "ue" and "oe", or to add support for transliterating Russian
-
# to ASCII.
-
#
-
# In order to make your custom transliterations available, you must set
-
# them as the <tt>i18n.transliterate.rule</tt> i18n key:
-
#
-
# # Store the transliterations in locales/de.yml
-
# i18n:
-
# transliterate:
-
# rule:
-
# ü: "ue"
-
# ö: "oe"
-
#
-
# # Or set them using Ruby
-
# I18n.backend.store_translations(:de, i18n: {
-
# transliterate: {
-
# rule: {
-
# 'ü' => 'ue',
-
# 'ö' => 'oe'
-
# }
-
# }
-
# })
-
#
-
# The value for <tt>i18n.transliterate.rule</tt> can be a simple Hash that
-
# maps characters to ASCII approximations as shown above, or, for more
-
# complex requirements, a Proc:
-
#
-
# I18n.backend.store_translations(:de, i18n: {
-
# transliterate: {
-
# rule: ->(string) { MyTransliterator.transliterate(string) }
-
# }
-
# })
-
#
-
# Now you can have different transliterations for each locale:
-
#
-
# I18n.locale = :en
-
# transliterate('Jürgen')
-
# # => "Jurgen"
-
#
-
# I18n.locale = :de
-
# transliterate('Jürgen')
-
# # => "Juergen"
-
1
def transliterate(string, replacement = "?")
-
I18n.transliterate(ActiveSupport::Multibyte::Unicode.normalize(
-
ActiveSupport::Multibyte::Unicode.tidy_bytes(string), :c),
-
:replacement => replacement)
-
end
-
-
# Replaces special characters in a string so that it may be used as part of
-
# a 'pretty' URL.
-
#
-
# class Person
-
# def to_param
-
# "#{id}-#{name.parameterize}"
-
# end
-
# end
-
#
-
# @person = Person.find(1)
-
# # => #<Person id: 1, name: "Donald E. Knuth">
-
#
-
# <%= link_to(@person.name, person_path(@person)) %>
-
# # => <a href="/person/1-donald-e-knuth">Donald E. Knuth</a>
-
1
def parameterize(string, sep = '-')
-
# replace accented chars with their ascii equivalents
-
parameterized_string = transliterate(string)
-
# Turn unwanted chars into the separator
-
parameterized_string.gsub!(/[^a-z0-9\-_]+/i, sep)
-
unless sep.nil? || sep.empty?
-
re_sep = Regexp.escape(sep)
-
# No more than one of the separator in a row.
-
parameterized_string.gsub!(/#{re_sep}{2,}/, sep)
-
# Remove leading/trailing separator.
-
parameterized_string.gsub!(/^#{re_sep}|#{re_sep}$/i, '')
-
end
-
parameterized_string.downcase
-
end
-
-
end
-
end
-
1
require 'active_support/json/decoding'
-
1
require 'active_support/json/encoding'
-
1
require 'active_support/core_ext/module/attribute_accessors'
-
1
require 'active_support/core_ext/module/delegation'
-
1
require 'multi_json'
-
-
1
module ActiveSupport
-
# Look for and parse json strings that look like ISO 8601 times.
-
1
mattr_accessor :parse_json_times
-
-
1
module JSON
-
1
class << self
-
# Parses a JSON string (JavaScript Object Notation) into a hash.
-
# See www.json.org for more info.
-
#
-
# ActiveSupport::JSON.decode("{\"team\":\"rails\",\"players\":\"36\"}")
-
# => {"team" => "rails", "players" => "36"}
-
1
def decode(json, options ={})
-
3
data = MultiJson.load(json, options)
-
3
if ActiveSupport.parse_json_times
-
convert_dates_from(data)
-
else
-
3
data
-
end
-
end
-
-
1
def engine
-
MultiJson.adapter
-
end
-
1
alias :backend :engine
-
-
1
def engine=(name)
-
MultiJson.use(name)
-
end
-
1
alias :backend= :engine=
-
-
1
def with_backend(name)
-
old_backend, self.backend = backend, name
-
yield
-
ensure
-
self.backend = old_backend
-
end
-
-
# Returns the class of the error that will be raised when there is an
-
# error in decoding JSON. Using this method means you won't directly
-
# depend on the ActiveSupport's JSON implementation, in case it changes
-
# in the future.
-
#
-
# begin
-
# obj = ActiveSupport::JSON.decode(some_string)
-
# rescue ActiveSupport::JSON.parse_error
-
# Rails.logger.warn("Attempted to decode invalid JSON: #{some_string}")
-
# end
-
1
def parse_error
-
MultiJson::DecodeError
-
end
-
-
1
private
-
-
1
def convert_dates_from(data)
-
case data
-
when nil
-
nil
-
when DATE_REGEX
-
begin
-
DateTime.parse(data)
-
rescue ArgumentError
-
data
-
end
-
when Array
-
data.map! { |d| convert_dates_from(d) }
-
when Hash
-
data.each do |key, value|
-
data[key] = convert_dates_from(value)
-
end
-
else
-
data
-
end
-
end
-
end
-
end
-
end
-
1
require 'active_support/core_ext/object/to_json'
-
1
require 'active_support/core_ext/module/delegation'
-
1
require 'active_support/json/variable'
-
-
1
require 'bigdecimal'
-
1
require 'active_support/core_ext/big_decimal/conversions' # for #to_s
-
1
require 'active_support/core_ext/hash/except'
-
1
require 'active_support/core_ext/hash/slice'
-
1
require 'active_support/core_ext/object/instance_variables'
-
1
require 'time'
-
1
require 'active_support/core_ext/time/conversions'
-
1
require 'active_support/core_ext/date_time/conversions'
-
1
require 'active_support/core_ext/date/conversions'
-
1
require 'set'
-
-
1
module ActiveSupport
-
1
class << self
-
1
delegate :use_standard_json_time_format, :use_standard_json_time_format=,
-
:escape_html_entities_in_json, :escape_html_entities_in_json=,
-
:encode_big_decimal_as_string, :encode_big_decimal_as_string=,
-
:to => :'ActiveSupport::JSON::Encoding'
-
end
-
-
1
module JSON
-
# matches YAML-formatted dates
-
1
DATE_REGEX = /^(?:\d{4}-\d{2}-\d{2}|\d{4}-\d{1,2}-\d{1,2}[T \t]+\d{1,2}:\d{2}:\d{2}(\.[0-9]*)?(([ \t]*)Z|[-+]\d{2}?(:\d{2})?))$/
-
-
# Dumps objects in JSON (JavaScript Object Notation).
-
# See www.json.org for more info.
-
#
-
# ActiveSupport::JSON.encode({ team: 'rails', players: '36' })
-
# # => "{\"team\":\"rails\",\"players\":\"36\"}"
-
1
def self.encode(value, options = nil)
-
83
Encoding::Encoder.new(options).encode(value)
-
end
-
-
1
module Encoding #:nodoc:
-
1
class CircularReferenceError < StandardError; end
-
-
1
class Encoder
-
1
attr_reader :options
-
-
1
def initialize(options = nil)
-
338
@options = options || {}
-
338
@seen = Set.new
-
end
-
-
1
def encode(value, use_options = true)
-
1141
check_for_circular_references(value) do
-
1141
jsonified = use_options ? value.as_json(options_for(value)) : value.as_json
-
1141
jsonified.encode_json(self)
-
end
-
end
-
-
# like encode, but only calls as_json, without encoding to string.
-
1
def as_json(value, use_options = true)
-
981
check_for_circular_references(value) do
-
981
use_options ? value.as_json(options_for(value)) : value.as_json
-
end
-
end
-
-
1
def options_for(value)
-
668
if value.is_a?(Array) || value.is_a?(Hash)
-
# hashes and arrays need to get encoder in the options, so that
-
# they can detect circular references.
-
57
options.merge(:encoder => self)
-
else
-
611
options
-
end
-
end
-
-
1
def escape(string)
-
684
Encoding.escape(string)
-
end
-
-
1
private
-
1
def check_for_circular_references(value)
-
2122
unless @seen.add?(value.__id__)
-
raise CircularReferenceError, 'object references itself'
-
end
-
2122
yield
-
ensure
-
2122
@seen.delete(value.__id__)
-
end
-
end
-
-
-
1
ESCAPED_CHARS = {
-
"\x00" => '\u0000', "\x01" => '\u0001', "\x02" => '\u0002',
-
"\x03" => '\u0003', "\x04" => '\u0004', "\x05" => '\u0005',
-
"\x06" => '\u0006', "\x07" => '\u0007', "\x0B" => '\u000B',
-
"\x0E" => '\u000E', "\x0F" => '\u000F', "\x10" => '\u0010',
-
"\x11" => '\u0011', "\x12" => '\u0012', "\x13" => '\u0013',
-
"\x14" => '\u0014', "\x15" => '\u0015', "\x16" => '\u0016',
-
"\x17" => '\u0017', "\x18" => '\u0018', "\x19" => '\u0019',
-
"\x1A" => '\u001A', "\x1B" => '\u001B', "\x1C" => '\u001C',
-
"\x1D" => '\u001D', "\x1E" => '\u001E', "\x1F" => '\u001F',
-
"\010" => '\b',
-
"\f" => '\f',
-
"\n" => '\n',
-
"\r" => '\r',
-
"\t" => '\t',
-
'"' => '\"',
-
'\\' => '\\\\',
-
'>' => '\u003E',
-
'<' => '\u003C',
-
'&' => '\u0026' }
-
-
1
class << self
-
# If true, use ISO 8601 format for dates and times. Otherwise, fall back
-
# to the Active Support legacy format.
-
1
attr_accessor :use_standard_json_time_format
-
-
# If false, serializes BigDecimal objects as numeric instead of wrapping
-
# them in a string.
-
1
attr_accessor :encode_big_decimal_as_string
-
-
1
attr_accessor :escape_regex
-
1
attr_reader :escape_html_entities_in_json
-
-
1
def escape_html_entities_in_json=(value)
-
1
self.escape_regex = \
-
if @escape_html_entities_in_json = value
-
1
/[\x00-\x1F"\\><&]/
-
else
-
/[\x00-\x1F"\\]/
-
end
-
end
-
-
1
def escape(string)
-
684
string = string.encode(::Encoding::UTF_8, :undef => :replace).force_encoding(::Encoding::BINARY)
-
684
json = string.
-
4
gsub(escape_regex) { |s| ESCAPED_CHARS[s] }.
-
gsub(/([\xC0-\xDF][\x80-\xBF]|
-
[\xE0-\xEF][\x80-\xBF]{2}|
-
[\xF0-\xF7][\x80-\xBF]{3})+/nx) { |s|
-
s.unpack("U*").pack("n*").unpack("H*")[0].gsub(/.{4}/n, '\\\\u\&')
-
}
-
684
json = %("#{json}")
-
684
json.force_encoding(::Encoding::UTF_8)
-
684
json
-
end
-
end
-
-
1
self.use_standard_json_time_format = true
-
1
self.escape_html_entities_in_json = true
-
1
self.encode_big_decimal_as_string = true
-
end
-
end
-
end
-
-
1
class Object
-
1
def as_json(options = nil) #:nodoc:
-
if respond_to?(:to_hash)
-
to_hash
-
else
-
instance_values
-
end
-
end
-
end
-
-
1
class Struct #:nodoc:
-
1
def as_json(options = nil)
-
Hash[members.zip(values)]
-
end
-
end
-
-
1
class TrueClass
-
1
def as_json(options = nil) #:nodoc:
-
58
self
-
end
-
-
1
def encode_json(encoder) #:nodoc:
-
29
to_s
-
end
-
end
-
-
1
class FalseClass
-
1
def as_json(options = nil) #:nodoc:
-
2
self
-
end
-
-
1
def encode_json(encoder) #:nodoc:
-
1
to_s
-
end
-
end
-
-
1
class NilClass
-
1
def as_json(options = nil) #:nodoc:
-
70
self
-
end
-
-
1
def encode_json(encoder) #:nodoc:
-
32
'null'
-
end
-
end
-
-
1
class String
-
1
def as_json(options = nil) #:nodoc:
-
915
self
-
end
-
-
1
def encode_json(encoder) #:nodoc:
-
684
encoder.escape(self)
-
end
-
end
-
-
1
class Symbol
-
1
def as_json(options = nil) #:nodoc:
-
to_s
-
end
-
end
-
-
1
class Numeric
-
1
def as_json(options = nil) #:nodoc:
-
771
self
-
end
-
-
1
def encode_json(encoder) #:nodoc:
-
263
to_s
-
end
-
end
-
-
1
class Float
-
# Encoding Infinity or NaN to JSON should return "null". The default returns
-
# "Infinity" or "NaN" which breaks parsing the JSON. E.g. JSON.parse('[NaN]').
-
1
def as_json(options = nil) #:nodoc:
-
finite? ? self : nil
-
end
-
end
-
-
1
class BigDecimal
-
# A BigDecimal would be naturally represented as a JSON number. Most libraries,
-
# however, parse non-integer JSON numbers directly as floats. Clients using
-
# those libraries would get in general a wrong number and no way to recover
-
# other than manually inspecting the string with the JSON code itself.
-
#
-
# That's why a JSON string is returned. The JSON literal is not numeric, but
-
# if the other end knows by contract that the data is supposed to be a
-
# BigDecimal, it still has the chance to post-process the string and get the
-
# real value.
-
#
-
# Use <tt>ActiveSupport.use_standard_json_big_decimal_format = true</tt> to
-
# override this behaviour.
-
1
def as_json(options = nil) #:nodoc:
-
if finite?
-
ActiveSupport.encode_big_decimal_as_string ? to_s : self
-
else
-
nil
-
end
-
end
-
end
-
-
1
class Regexp
-
1
def as_json(options = nil) #:nodoc:
-
to_s
-
end
-
end
-
-
1
module Enumerable
-
1
def as_json(options = nil) #:nodoc:
-
to_a.as_json(options)
-
end
-
end
-
-
1
class Range
-
1
def as_json(options = nil) #:nodoc:
-
to_s
-
end
-
end
-
-
1
class Array
-
1
def as_json(options = nil) #:nodoc:
-
# use encoder as a proxy to call as_json on all elements, to protect from circular references
-
52
encoder = options && options[:encoder] || ActiveSupport::JSON::Encoding::Encoder.new(options)
-
172
map { |v| encoder.as_json(v, options) }
-
end
-
-
1
def encode_json(encoder) #:nodoc:
-
# we assume here that the encoder has already run as_json on self and the elements, so we run encode_json directly
-
82
"[#{map { |v| v.encode_json(encoder) } * ','}]"
-
end
-
end
-
-
1
class Hash
-
1
def as_json(options = nil) #:nodoc:
-
# create a subset of the hash by applying :only or :except
-
214
subset = if options
-
53
if attrs = options[:only]
-
1
slice(*Array(attrs))
-
elsif attrs = options[:except]
-
except(*Array(attrs))
-
else
-
52
self
-
end
-
else
-
161
self
-
end
-
-
# use encoder as a proxy to call as_json on all values in the subset, to protect from circular references
-
214
encoder = options && options[:encoder] || ActiveSupport::JSON::Encoding::Encoder.new(options)
-
1075
Hash[subset.map { |k, v| [k.to_s, encoder.as_json(v, options)] }]
-
end
-
-
1
def encode_json(encoder) #:nodoc:
-
# values are encoded with use_options = false, because we don't want hash representations from ActiveModel to be
-
# processed once again with as_json with options, as this could cause unexpected results (i.e. missing fields);
-
-
# on the other hand, we need to run as_json on the elements, because the model representation may contain fields
-
# like Time/Date in their original (not jsonified) form, etc.
-
-
695
"{#{map { |k,v| "#{encoder.encode(k.to_s)}:#{encoder.encode(v, false)}" } * ','}}"
-
end
-
end
-
-
1
class Time
-
1
def as_json(options = nil) #:nodoc:
-
11
if ActiveSupport.use_standard_json_time_format
-
11
xmlschema
-
else
-
%(#{strftime("%Y/%m/%d %H:%M:%S")} #{formatted_offset(false)})
-
end
-
end
-
end
-
-
1
class Date
-
1
def as_json(options = nil) #:nodoc:
-
if ActiveSupport.use_standard_json_time_format
-
strftime("%Y-%m-%d")
-
else
-
strftime("%Y/%m/%d")
-
end
-
end
-
end
-
-
1
class DateTime
-
1
def as_json(options = nil) #:nodoc:
-
if ActiveSupport.use_standard_json_time_format
-
xmlschema
-
else
-
strftime('%Y/%m/%d %H:%M:%S %z')
-
end
-
end
-
end
-
1
require 'active_support/deprecation'
-
-
1
module ActiveSupport
-
1
module JSON
-
# Deprecated: A string that returns itself as its JSON-encoded form.
-
1
class Variable < String
-
1
def initialize(*args)
-
message = 'ActiveSupport::JSON::Variable is deprecated and will be removed in Rails 4.1. ' \
-
'For your own custom JSON literals, define #as_json and #encode_json yourself.'
-
ActiveSupport::Deprecation.warn message
-
super
-
end
-
-
1
def as_json(options = nil) self end #:nodoc:
-
1
def encode_json(encoder) self end #:nodoc:
-
end
-
end
-
end
-
1
module ActiveSupport
-
# lazy_load_hooks allows rails to lazily load a lot of components and thus
-
# making the app boot faster. Because of this feature now there is no need to
-
# require <tt>ActiveRecord::Base</tt> at boot time purely to apply
-
# configuration. Instead a hook is registered that applies configuration once
-
# <tt>ActiveRecord::Base</tt> is loaded. Here <tt>ActiveRecord::Base</tt> is
-
# used as example but this feature can be applied elsewhere too.
-
#
-
# Here is an example where +on_load+ method is called to register a hook.
-
#
-
# initializer 'active_record.initialize_timezone' do
-
# ActiveSupport.on_load(:active_record) do
-
# self.time_zone_aware_attributes = true
-
# self.default_timezone = :utc
-
# end
-
# end
-
#
-
# When the entirety of +activerecord/lib/active_record/base.rb+ has been
-
# evaluated then +run_load_hooks+ is invoked. The very last line of
-
# +activerecord/lib/active_record/base.rb+ is:
-
#
-
# ActiveSupport.run_load_hooks(:active_record, ActiveRecord::Base)
-
3
@load_hooks = Hash.new { |h,k| h[k] = [] }
-
3
@loaded = Hash.new { |h,k| h[k] = [] }
-
-
1
def self.on_load(name, options = {}, &block)
-
4
@loaded[name].each do |base|
-
2
execute_hook(base, options, block)
-
end
-
-
4
@load_hooks[name] << [block, options]
-
end
-
-
1
def self.execute_hook(base, options, block)
-
4
if options[:yield]
-
block.call(base)
-
else
-
4
base.instance_eval(&block)
-
end
-
end
-
-
1
def self.run_load_hooks(name, base = Object)
-
2
@loaded[name] << base
-
2
@load_hooks[name].each do |hook, options|
-
2
execute_hook(base, options, hook)
-
end
-
end
-
end
-
1
require 'active_support/core_ext/module/attribute_accessors'
-
1
require 'active_support/core_ext/class/attribute'
-
-
1
module ActiveSupport
-
# ActiveSupport::LogSubscriber is an object set to consume
-
# ActiveSupport::Notifications with the sole purpose of logging them.
-
# The log subscriber dispatches notifications to a registered object based
-
# on its given namespace.
-
#
-
# An example would be Active Record log subscriber responsible for logging
-
# queries:
-
#
-
# module ActiveRecord
-
# class LogSubscriber < ActiveSupport::LogSubscriber
-
# def sql(event)
-
# "#{event.payload[:name]} (#{event.duration}) #{event.payload[:sql]}"
-
# end
-
# end
-
# end
-
#
-
# And it's finally registered as:
-
#
-
# ActiveRecord::LogSubscriber.attach_to :active_record
-
#
-
# Since we need to know all instance methods before attaching the log
-
# subscriber, the line above should be called after your
-
# <tt>ActiveRecord::LogSubscriber</tt> definition.
-
#
-
# After configured, whenever a "sql.active_record" notification is published,
-
# it will properly dispatch the event (ActiveSupport::Notifications::Event) to
-
# the sql method.
-
#
-
# Log subscriber also has some helpers to deal with logging and automatically
-
# flushes all logs when the request finishes (via action_dispatch.callback
-
# notification) in a Rails environment.
-
1
class LogSubscriber
-
# Embed in a String to clear all previous ANSI sequences.
-
1
CLEAR = "\e[0m"
-
1
BOLD = "\e[1m"
-
-
# Colors
-
1
BLACK = "\e[30m"
-
1
RED = "\e[31m"
-
1
GREEN = "\e[32m"
-
1
YELLOW = "\e[33m"
-
1
BLUE = "\e[34m"
-
1
MAGENTA = "\e[35m"
-
1
CYAN = "\e[36m"
-
1
WHITE = "\e[37m"
-
-
1
mattr_accessor :colorize_logging
-
1
self.colorize_logging = true
-
-
1
class << self
-
1
def logger
-
@logger ||= Rails.logger if defined?(Rails)
-
@logger
-
end
-
-
1
attr_writer :logger
-
-
1
def attach_to(namespace, log_subscriber=new, notifier=ActiveSupport::Notifications)
-
8
log_subscribers << log_subscriber
-
-
8
log_subscriber.public_methods(false).each do |event|
-
32
next if %w{ start finish }.include?(event.to_s)
-
-
32
notifier.subscribe("#{event}.#{namespace}", log_subscriber)
-
end
-
end
-
-
1
def log_subscribers
-
15
@@log_subscribers ||= []
-
end
-
-
# Flush all log_subscribers' logger.
-
1
def flush_all!
-
logger.flush if logger.respond_to?(:flush)
-
end
-
end
-
-
1
def initialize
-
10
@queue_key = [self.class.name, object_id].join "-"
-
10
super
-
end
-
-
1
def logger
-
LogSubscriber.logger
-
end
-
-
1
def start(name, id, payload)
-
67856
return unless logger
-
-
67840
e = ActiveSupport::Notifications::Event.new(name, Time.now, nil, id, payload)
-
67840
parent = event_stack.last
-
67840
parent << e if parent
-
-
67840
event_stack.push e
-
end
-
-
1
def finish(name, id, payload)
-
67856
return unless logger
-
-
67840
finished = Time.now
-
67840
event = event_stack.pop
-
67840
event.end = finished
-
67840
event.payload.merge!(payload)
-
-
67840
method = name.split('.').first
-
67840
begin
-
67840
send(method, event)
-
7
rescue Exception => e
-
7
logger.error "Could not log #{name.inspect} event. #{e.class}: #{e.message} #{e.backtrace}"
-
end
-
end
-
-
1
protected
-
-
1
%w(info debug warn error fatal unknown).each do |level|
-
6
class_eval <<-METHOD, __FILE__, __LINE__ + 1
-
def #{level}(progname = nil, &block)
-
logger.#{level}(progname, &block) if logger
-
end
-
METHOD
-
end
-
-
# Set color by using a string or one of the defined constants. If a third
-
# option is set to +true+, it also adds bold to the string. This is based
-
# on the Highline implementation and will automatically append CLEAR to the
-
# end of the returned String.
-
1
def color(text, color, bold=false)
-
69255
return text unless colorize_logging
-
43009
color = self.class.const_get(color.upcase) if color.is_a?(Symbol)
-
43009
bold = bold ? BOLD : ""
-
43009
"#{bold}#{color}#{text}#{CLEAR}"
-
end
-
-
1
private
-
-
1
def event_stack
-
203520
Thread.current[@queue_key] ||= []
-
end
-
end
-
end
-
1
require 'simplecov'
-
1
SimpleCov.start
-
1
require 'active_support/log_subscriber'
-
1
require 'active_support/buffered_logger'
-
1
require 'active_support/notifications'
-
-
1
module ActiveSupport
-
1
class LogSubscriber
-
# Provides some helpers to deal with testing log subscribers by setting up
-
# notifications. Take for instance Active Record subscriber tests:
-
#
-
# class SyncLogSubscriberTest < ActiveSupport::TestCase
-
# include ActiveSupport::LogSubscriber::TestHelper
-
#
-
# def setup
-
# ActiveRecord::LogSubscriber.attach_to(:active_record)
-
# end
-
#
-
# def test_basic_query_logging
-
# Developer.all
-
# wait
-
# assert_equal 1, @logger.logged(:debug).size
-
# assert_match(/Developer Load/, @logger.logged(:debug).last)
-
# assert_match(/SELECT \* FROM "developers"/, @logger.logged(:debug).last)
-
# end
-
# end
-
#
-
# All you need to do is to ensure that your log subscriber is added to
-
# Rails::Subscriber, as in the second line of the code above. The test
-
# helpers are responsible for setting up the queue, subscriptions and
-
# turning colors in logs off.
-
#
-
# The messages are available in the @logger instance, which is a logger with
-
# limited powers (it actually does not send anything to your output), and
-
# you can collect them doing @logger.logged(level), where level is the level
-
# used in logging, like info, debug, warn and so on.
-
1
module TestHelper
-
1
def setup
-
7
@logger = MockLogger.new
-
7
@notifier = ActiveSupport::Notifications::Fanout.new
-
-
7
ActiveSupport::LogSubscriber.colorize_logging = false
-
-
7
@old_notifier = ActiveSupport::Notifications.notifier
-
7
set_logger(@logger)
-
7
ActiveSupport::Notifications.notifier = @notifier
-
end
-
-
1
def teardown
-
7
set_logger(nil)
-
7
ActiveSupport::Notifications.notifier = @old_notifier
-
end
-
-
1
class MockLogger
-
1
include ActiveSupport::Logger::Severity
-
-
1
attr_reader :flush_count
-
1
attr_accessor :level
-
-
1
def initialize(level = DEBUG)
-
7
@flush_count = 0
-
7
@level = level
-
12
@logged = Hash.new { |h,k| h[k] = [] }
-
end
-
-
1
def method_missing(level, message = nil)
-
4
if block_given?
-
@logged[level] << yield
-
else
-
4
@logged[level] << message
-
end
-
end
-
-
1
def logged(level)
-
23
@logged[level].compact.map { |l| l.to_s.strip }
-
end
-
-
1
def flush
-
@flush_count += 1
-
end
-
-
1
ActiveSupport::Logger::Severity.constants.each do |severity|
-
6
class_eval <<-EOT, __FILE__, __LINE__ + 1
-
def #{severity.downcase}?
-
#{severity} >= @level
-
end
-
EOT
-
end
-
end
-
-
# Wait notifications to be published.
-
1
def wait
-
5
@notifier.wait
-
end
-
-
# Overwrite if you use another logger in your log subscriber.
-
#
-
# def logger
-
# ActiveRecord::Base.logger = @logger
-
# end
-
1
def set_logger(logger)
-
ActiveSupport::LogSubscriber.logger = logger
-
end
-
end
-
end
-
end
-
1
require 'logger'
-
-
1
module ActiveSupport
-
1
class Logger < ::Logger
-
# Broadcasts logs to multiple loggers.
-
1
def self.broadcast(logger) # :nodoc:
-
Module.new do
-
define_method(:add) do |*args, &block|
-
logger.add(*args, &block)
-
super(*args, &block)
-
end
-
-
define_method(:<<) do |x|
-
logger << x
-
super(x)
-
end
-
-
define_method(:close) do
-
logger.close
-
super()
-
end
-
-
define_method(:progname=) do |name|
-
logger.progname = name
-
super(name)
-
end
-
-
define_method(:formatter=) do |formatter|
-
logger.formatter = formatter
-
super(formatter)
-
end
-
-
define_method(:level=) do |level|
-
logger.level = level
-
super(level)
-
end
-
end
-
end
-
-
1
def initialize(*args)
-
5
super
-
5
@formatter = SimpleFormatter.new
-
end
-
-
# Simple formatter which only displays the message.
-
1
class SimpleFormatter < ::Logger::Formatter
-
# This method is invoked when a log event occurs
-
1
def call(severity, timestamp, progname, msg)
-
46683
"#{String === msg ? msg : msg.inspect}\n"
-
end
-
end
-
end
-
end
-
1
module ActiveSupport #:nodoc:
-
1
module Multibyte
-
1
autoload :Chars, 'active_support/multibyte/chars'
-
1
autoload :Unicode, 'active_support/multibyte/unicode'
-
-
# The proxy class returned when calling mb_chars. You can use this accessor
-
# to configure your own proxy class so you can support other encodings. See
-
# the ActiveSupport::Multibyte::Chars implementation for an example how to
-
# do this.
-
#
-
# ActiveSupport::Multibyte.proxy_class = CharsForUTF32
-
1
def self.proxy_class=(klass)
-
@proxy_class = klass
-
end
-
-
# Returns the current proxy class.
-
1
def self.proxy_class
-
6
@proxy_class ||= ActiveSupport::Multibyte::Chars
-
end
-
end
-
end
-
# encoding: utf-8
-
1
require 'active_support/json'
-
1
require 'active_support/core_ext/string/access'
-
1
require 'active_support/core_ext/string/behavior'
-
1
require 'active_support/core_ext/module/delegation'
-
-
1
module ActiveSupport #:nodoc:
-
1
module Multibyte #:nodoc:
-
# Chars enables you to work transparently with UTF-8 encoding in the Ruby
-
# String class without having extensive knowledge about the encoding. A
-
# Chars object accepts a string upon initialization and proxies String
-
# methods in an encoding safe manner. All the normal String methods are also
-
# implemented on the proxy.
-
#
-
# String methods are proxied through the Chars object, and can be accessed
-
# through the +mb_chars+ method. Methods which would normally return a
-
# String object now return a Chars object so methods can be chained.
-
#
-
# 'The Perfect String '.mb_chars.downcase.strip.normalize # => "the perfect string"
-
#
-
# Chars objects are perfectly interchangeable with String objects as long as
-
# no explicit class checks are made. If certain methods do explicitly check
-
# the class, call +to_s+ before you pass chars objects to them.
-
#
-
# bad.explicit_checking_method 'T'.mb_chars.downcase.to_s
-
#
-
# The default Chars implementation assumes that the encoding of the string
-
# is UTF-8, if you want to handle different encodings you can write your own
-
# multibyte string handler and configure it through
-
# ActiveSupport::Multibyte.proxy_class.
-
#
-
# class CharsForUTF32
-
# def size
-
# @wrapped_string.size / 4
-
# end
-
#
-
# def self.accepts?(string)
-
# string.length % 4 == 0
-
# end
-
# end
-
#
-
# ActiveSupport::Multibyte.proxy_class = CharsForUTF32
-
1
class Chars
-
1
include Comparable
-
1
attr_reader :wrapped_string
-
1
alias to_s wrapped_string
-
1
alias to_str wrapped_string
-
-
1
delegate :<=>, :=~, :acts_like_string?, :to => :wrapped_string
-
-
# Creates a new Chars instance by wrapping _string_.
-
1
def initialize(string)
-
3
@wrapped_string = string
-
3
@wrapped_string.force_encoding(Encoding::UTF_8) unless @wrapped_string.frozen?
-
end
-
-
# Forward all undefined methods to the wrapped string.
-
1
def method_missing(method, *args, &block)
-
if method.to_s =~ /!$/
-
result = @wrapped_string.__send__(method, *args, &block)
-
self if result
-
else
-
result = @wrapped_string.__send__(method, *args, &block)
-
result.kind_of?(String) ? chars(result) : result
-
end
-
end
-
-
# Returns +true+ if _obj_ responds to the given method. Private methods
-
# are included in the search only if the optional second parameter
-
# evaluates to +true+.
-
1
def respond_to_missing?(method, include_private)
-
3
@wrapped_string.respond_to?(method, include_private)
-
end
-
-
# Returns +true+ when the proxy class can handle the string. Returns
-
# +false+ otherwise.
-
1
def self.consumes?(string)
-
6
string.encoding == Encoding::UTF_8
-
end
-
-
# Works just like <tt>String#split</tt>, with the exception that the items
-
# in the resulting list are Chars instances instead of String. This makes
-
# chaining methods easier.
-
#
-
# 'Café périferôl'.mb_chars.split(/é/).map { |part| part.upcase.to_s } # => ["CAF", " P", "RIFERÔL"]
-
1
def split(*args)
-
@wrapped_string.split(*args).map { |i| self.class.new(i) }
-
end
-
-
# Works like like <tt>String#slice!</tt>, but returns an instance of
-
# Chars, or nil if the string was not modified.
-
1
def slice!(*args)
-
chars(@wrapped_string.slice!(*args))
-
end
-
-
# Reverses all characters in the string.
-
#
-
# 'Café'.mb_chars.reverse.to_s # => 'éfaC'
-
1
def reverse
-
chars(Unicode.unpack_graphemes(@wrapped_string).reverse.flatten.pack('U*'))
-
end
-
-
# Limits the byte size of the string to a number of bytes without breaking
-
# characters. Usable when the storage for a string is limited for some
-
# reason.
-
#
-
# 'こんにちは'.mb_chars.limit(7).to_s # => "こん"
-
1
def limit(limit)
-
slice(0...translate_offset(limit))
-
end
-
-
# Converts characters in the string to uppercase.
-
#
-
# 'Laurent, où sont les tests ?'.mb_chars.upcase.to_s # => "LAURENT, OÙ SONT LES TESTS ?"
-
1
def upcase
-
chars Unicode.upcase(@wrapped_string)
-
end
-
-
# Converts characters in the string to lowercase.
-
#
-
# 'VĚDA A VÝZKUM'.mb_chars.downcase.to_s # => "věda a výzkum"
-
1
def downcase
-
chars Unicode.downcase(@wrapped_string)
-
end
-
-
# Converts characters in the string to the opposite case.
-
#
-
# 'El Cañón".mb_chars.swapcase.to_s # => "eL cAÑÓN"
-
1
def swapcase
-
chars Unicode.swapcase(@wrapped_string)
-
end
-
-
# Converts the first character to uppercase and the remainder to lowercase.
-
#
-
# 'über'.mb_chars.capitalize.to_s # => "Über"
-
1
def capitalize
-
(slice(0) || chars('')).upcase + (slice(1..-1) || chars('')).downcase
-
end
-
-
# Capitalizes the first letter of every word, when possible.
-
#
-
# "ÉL QUE SE ENTERÓ".mb_chars.titleize # => "Él Que Se Enteró"
-
# "日本語".mb_chars.titleize # => "日本語"
-
1
def titleize
-
chars(downcase.to_s.gsub(/\b('?\S)/u) { Unicode.upcase($1)})
-
end
-
1
alias_method :titlecase, :titleize
-
-
# Returns the KC normalization of the string by default. NFKC is
-
# considered the best normalization form for passing strings to databases
-
# and validations.
-
#
-
# * <tt>form</tt> - The form you want to normalize in. Should be one of the following:
-
# <tt>:c</tt>, <tt>:kc</tt>, <tt>:d</tt>, or <tt>:kd</tt>. Default is
-
# ActiveSupport::Multibyte::Unicode.default_normalization_form
-
1
def normalize(form = nil)
-
chars(Unicode.normalize(@wrapped_string, form))
-
end
-
-
# Performs canonical decomposition on all the characters.
-
#
-
# 'é'.length # => 2
-
# 'é'.mb_chars.decompose.to_s.length # => 3
-
1
def decompose
-
chars(Unicode.decompose(:canonical, @wrapped_string.codepoints.to_a).pack('U*'))
-
end
-
-
# Performs composition on all the characters.
-
#
-
# 'é'.length # => 3
-
# 'é'.mb_chars.compose.to_s.length # => 2
-
1
def compose
-
chars(Unicode.compose(@wrapped_string.codepoints.to_a).pack('U*'))
-
end
-
-
# Returns the number of grapheme clusters in the string.
-
#
-
# 'क्षि'.mb_chars.length # => 4
-
# 'क्षि'.mb_chars.grapheme_length # => 3
-
1
def grapheme_length
-
Unicode.unpack_graphemes(@wrapped_string).length
-
end
-
-
# Replaces all ISO-8859-1 or CP1252 characters by their UTF-8 equivalent
-
# resulting in a valid UTF-8 string.
-
#
-
# Passing +true+ will forcibly tidy all bytes, assuming that the string's
-
# encoding is entirely CP1252 or ISO-8859-1.
-
1
def tidy_bytes(force = false)
-
chars(Unicode.tidy_bytes(@wrapped_string, force))
-
end
-
-
1
def as_json(options = nil) #:nodoc:
-
to_s.as_json(options)
-
end
-
-
1
%w(capitalize downcase reverse tidy_bytes upcase).each do |method|
-
5
define_method("#{method}!") do |*args|
-
@wrapped_string = send(method, *args).to_s
-
self
-
end
-
end
-
-
1
protected
-
-
1
def translate_offset(byte_offset) #:nodoc:
-
return nil if byte_offset.nil?
-
return 0 if @wrapped_string == ''
-
-
begin
-
@wrapped_string.byteslice(0...byte_offset).unpack('U*').length
-
rescue ArgumentError
-
byte_offset -= 1
-
retry
-
end
-
end
-
-
1
def chars(string) #:nodoc:
-
self.class.new(string)
-
end
-
end
-
end
-
end
-
1
require 'active_support/notifications/instrumenter'
-
1
require 'active_support/notifications/fanout'
-
-
1
module ActiveSupport
-
# = Notifications
-
#
-
# <tt>ActiveSupport::Notifications</tt> provides an instrumentation API for
-
# Ruby.
-
#
-
# == Instrumenters
-
#
-
# To instrument an event you just need to do:
-
#
-
# ActiveSupport::Notifications.instrument('render', extra: :information) do
-
# render text: 'Foo'
-
# end
-
#
-
# That executes the block first and notifies all subscribers once done.
-
#
-
# In the example above +render+ is the name of the event, and the rest is called
-
# the _payload_. The payload is a mechanism that allows instrumenters to pass
-
# extra information to subscribers. Payloads consist of a hash whose contents
-
# are arbitrary and generally depend on the event.
-
#
-
# == Subscribers
-
#
-
# You can consume those events and the information they provide by registering
-
# a subscriber.
-
#
-
# ActiveSupport::Notifications.subscribe('render') do |name, start, finish, id, payload|
-
# name # => String, name of the event (such as 'render' from above)
-
# start # => Time, when the instrumented block started execution
-
# finish # => Time, when the instrumented block ended execution
-
# id # => String, unique ID for this notification
-
# payload # => Hash, the payload
-
# end
-
#
-
# For instance, let's store all "render" events in an array:
-
#
-
# events = []
-
#
-
# ActiveSupport::Notifications.subscribe('render') do |*args|
-
# events << ActiveSupport::Notifications::Event.new(*args)
-
# end
-
#
-
# That code returns right away, you are just subscribing to "render" events.
-
# The block is saved and will be called whenever someone instruments "render":
-
#
-
# ActiveSupport::Notifications.instrument('render', extra: :information) do
-
# render text: 'Foo'
-
# end
-
#
-
# event = events.first
-
# event.name # => "render"
-
# event.duration # => 10 (in milliseconds)
-
# event.payload # => { extra: :information }
-
#
-
# The block in the <tt>subscribe</tt> call gets the name of the event, start
-
# timestamp, end timestamp, a string with a unique identifier for that event
-
# (something like "535801666f04d0298cd6"), and a hash with the payload, in
-
# that order.
-
#
-
# If an exception happens during that particular instrumentation the payload will
-
# have a key <tt>:exception</tt> with an array of two elements as value: a string with
-
# the name of the exception class, and the exception message.
-
#
-
# As the previous example depicts, the class <tt>ActiveSupport::Notifications::Event</tt>
-
# is able to take the arguments as they come and provide an object-oriented
-
# interface to that data.
-
#
-
# It is also possible to pass an object as the second parameter passed to the
-
# <tt>subscribe</tt> method instead of a block:
-
#
-
# module ActionController
-
# class PageRequest
-
# def call(name, started, finished, unique_id, payload)
-
# Rails.logger.debug ['notification:', name, started, finished, unique_id, payload].join(' ')
-
# end
-
# end
-
# end
-
#
-
# ActiveSupport::Notifications.subscribe('process_action.action_controller', ActionController::PageRequest.new)
-
#
-
# resulting in the following output within the logs including a hash with the payload:
-
#
-
# notification: process_action.action_controller 2012-04-13 01:08:35 +0300 2012-04-13 01:08:35 +0300 af358ed7fab884532ec7 {
-
# :controller=>"Devise::SessionsController",
-
# :action=>"new",
-
# :params=>{"action"=>"new", "controller"=>"devise/sessions"},
-
# :format=>:html,
-
# :method=>"GET",
-
# :path=>"/login/sign_in",
-
# :status=>200,
-
# :view_runtime=>279.3080806732178,
-
# :db_runtime=>40.053
-
# }
-
#
-
# You can also subscribe to all events whose name matches a certain regexp:
-
#
-
# ActiveSupport::Notifications.subscribe(/render/) do |*args|
-
# ...
-
# end
-
#
-
# and even pass no argument to <tt>subscribe</tt>, in which case you are subscribing
-
# to all events.
-
#
-
# == Temporary Subscriptions
-
#
-
# Sometimes you do not want to subscribe to an event for the entire life of
-
# the application. There are two ways to unsubscribe.
-
#
-
# WARNING: The instrumentation framework is designed for long-running subscribers,
-
# use this feature sparingly because it wipes some internal caches and that has
-
# a negative impact on performance.
-
#
-
# === Subscribe While a Block Runs
-
#
-
# You can subscribe to some event temporarily while some block runs. For
-
# example, in
-
#
-
# callback = lambda {|*args| ... }
-
# ActiveSupport::Notifications.subscribed(callback, "sql.active_record") do
-
# ...
-
# end
-
#
-
# the callback will be called for all "sql.active_record" events instrumented
-
# during the execution of the block. The callback is unsubscribed automatically
-
# after that.
-
#
-
# === Manual Unsubscription
-
#
-
# The +subscribe+ method returns a subscriber object:
-
#
-
# subscriber = ActiveSupport::Notifications.subscribe("render") do |*args|
-
# ...
-
# end
-
#
-
# To prevent that block from being called anymore, just unsubscribe passing
-
# that reference:
-
#
-
# ActiveSupport::Notifications.unsubscribe(subscriber)
-
#
-
# == Default Queue
-
#
-
# Notifications ships with a queue implementation that consumes and publish events
-
# to log subscribers in a thread. You can use any queue implementation you want.
-
#
-
1
module Notifications
-
1
class << self
-
1
attr_accessor :notifier
-
-
1
def publish(name, *args)
-
notifier.publish(name, *args)
-
end
-
-
1
def instrument(name, payload = {})
-
16
if notifier.listening?(name)
-
32
instrumenter.instrument(name, payload) { yield payload if block_given? }
-
else
-
yield payload if block_given?
-
end
-
end
-
-
1
def subscribe(*args, &block)
-
37
notifier.subscribe(*args, &block)
-
end
-
-
1
def subscribed(callback, *args, &block)
-
subscriber = subscribe(*args, &callback)
-
yield
-
ensure
-
unsubscribe(subscriber)
-
end
-
-
1
def unsubscribe(args)
-
3
notifier.unsubscribe(args)
-
end
-
-
1
def instrumenter
-
129
Thread.current[:"instrumentation_#{notifier.object_id}"] ||= Instrumenter.new(notifier)
-
end
-
end
-
-
1
self.notifier = Fanout.new
-
end
-
end
-
1
require 'mutex_m'
-
-
1
module ActiveSupport
-
1
module Notifications
-
# This is a default queue implementation that ships with Notifications.
-
# It just pushes events to all registered log subscribers.
-
#
-
# This class is thread safe. All methods are reentrant.
-
1
class Fanout
-
1
include Mutex_m
-
-
1
def initialize
-
8
@subscribers = []
-
8
@listeners_for = {}
-
8
super
-
end
-
-
1
def subscribe(pattern = nil, block = Proc.new)
-
37
subscriber = Subscribers.new pattern, block
-
37
synchronize do
-
37
@subscribers << subscriber
-
37
@listeners_for.clear
-
end
-
37
subscriber
-
end
-
-
1
def unsubscribe(subscriber)
-
3
synchronize do
-
27
@subscribers.reject! { |s| s.matches?(subscriber) }
-
3
@listeners_for.clear
-
end
-
end
-
-
1
def start(name, id, payload)
-
473125
listeners_for(name).each { |s| s.start(name, id, payload) }
-
end
-
-
1
def finish(name, id, payload)
-
473125
listeners_for(name).each { |s| s.finish(name, id, payload) }
-
end
-
-
1
def publish(name, *args)
-
listeners_for(name).each { |s| s.publish(name, *args) }
-
end
-
-
1
def listeners_for(name)
-
135728
synchronize do
-
135781
@listeners_for[name] ||= @subscribers.select { |s| s.subscribed_to?(name) }
-
end
-
end
-
-
1
def listening?(name)
-
16
listeners_for(name).any?
-
end
-
-
# This is a sync queue, so there is no waiting.
-
1
def wait
-
end
-
-
1
module Subscribers # :nodoc:
-
1
def self.new(pattern, listener)
-
37
if listener.respond_to?(:start) and listener.respond_to?(:finish)
-
33
subscriber = Evented.new pattern, listener
-
else
-
4
subscriber = Timed.new pattern, listener
-
end
-
-
37
unless pattern
-
AllMessages.new(subscriber)
-
else
-
37
subscriber
-
end
-
end
-
-
1
class Evented #:nodoc:
-
1
def initialize(pattern, delegate)
-
37
@pattern = pattern
-
37
@delegate = delegate
-
end
-
-
1
def start(name, id, payload)
-
135710
@delegate.start name, id, payload
-
end
-
-
1
def finish(name, id, payload)
-
135710
@delegate.finish name, id, payload
-
end
-
-
1
def subscribed_to?(name)
-
53
@pattern === name.to_s
-
end
-
-
1
def matches?(subscriber_or_name)
-
self === subscriber_or_name ||
-
24
@pattern && @pattern === subscriber_or_name
-
end
-
end
-
-
1
class Timed < Evented
-
1
def initialize(pattern, delegate)
-
4
@timestack = []
-
4
super
-
end
-
-
1
def publish(name, *args)
-
@delegate.call name, *args
-
end
-
-
1
def start(name, id, payload)
-
269559
@timestack.push Time.now
-
end
-
-
1
def finish(name, id, payload)
-
269559
started = @timestack.pop
-
269559
@delegate.call(name, started, Time.now, id, payload)
-
end
-
end
-
-
1
class AllMessages # :nodoc:
-
1
def initialize(delegate)
-
@delegate = delegate
-
end
-
-
1
def start(name, id, payload)
-
@delegate.start name, id, payload
-
end
-
-
1
def finish(name, id, payload)
-
@delegate.finish name, id, payload
-
end
-
-
1
def publish(name, *args)
-
@delegate.publish name, *args
-
end
-
-
1
def subscribed_to?(name)
-
true
-
end
-
-
1
alias :matches? :===
-
end
-
end
-
end
-
end
-
end
-
1
require 'securerandom'
-
-
1
module ActiveSupport
-
1
module Notifications
-
# Instrumentors are stored in a thread local.
-
1
class Instrumenter
-
1
attr_reader :id
-
-
1
def initialize(notifier)
-
15
@id = unique_id
-
15
@notifier = notifier
-
end
-
-
# Instrument the given block by measuring the time taken to execute it
-
# and publish it. Notice that events get sent even if an error occurs
-
# in the passed-in block.
-
1
def instrument(name, payload={})
-
67856
@notifier.start(name, @id, payload)
-
67856
begin
-
67856
yield
-
442
rescue Exception => e
-
442
payload[:exception] = [e.class.name, e.message]
-
442
raise e
-
ensure
-
67856
@notifier.finish(name, @id, payload)
-
67856
end
-
end
-
-
1
private
-
1
def unique_id
-
15
SecureRandom.hex(10)
-
end
-
end
-
-
1
class Event
-
1
attr_reader :name, :time, :transaction_id, :payload, :children
-
1
attr_accessor :end
-
-
1
def initialize(name, start, ending, transaction_id, payload)
-
67841
@name = name
-
67841
@payload = payload.dup
-
67841
@time = start
-
67841
@transaction_id = transaction_id
-
67841
@end = ending
-
67841
@children = []
-
end
-
-
1
def duration
-
114015
1000.0 * (self.end - time)
-
end
-
-
1
def <<(event)
-
18
@children << event
-
end
-
-
1
def parent_of?(event)
-
@children.include? event
-
end
-
end
-
end
-
end
-
1
require 'active_support/core_ext/hash/deep_merge'
-
-
1
module ActiveSupport
-
1
class OptionMerger #:nodoc:
-
1
instance_methods.each do |method|
-
135
undef_method(method) if method !~ /^(__|instance_eval|class|object_id)/
-
end
-
-
1
def initialize(context, options)
-
1
@context, @options = context, options
-
end
-
-
1
private
-
1
def method_missing(method, *arguments, &block)
-
5
if arguments.last.is_a?(Proc)
-
proc = arguments.pop
-
arguments << lambda { |*args| @options.deep_merge(proc.call(*args)) }
-
else
-
5
arguments << (arguments.last.respond_to?(:to_hash) ? @options.deep_merge(arguments.pop) : @options.dup)
-
end
-
-
5
@context.__send__(method, *arguments, &block)
-
end
-
end
-
end
-
# This is private interface.
-
#
-
# Rails components cherry pick from Active Support as needed, but there are a
-
# few features that are used for sure some way or another and it is not worth
-
# to put individual requires absolutely everywhere. Think blank? for example.
-
#
-
# This file is loaded by every Rails component except Active Support itself,
-
# but it does not belong to the Rails public interface. It is internal to
-
# Rails and can change anytime.
-
-
# Defines Object#blank? and Object#present?.
-
1
require 'active_support/core_ext/object/blank'
-
-
# Rails own autoload, eager_load, etc.
-
1
require 'active_support/dependencies/autoload'
-
-
# Support for ClassMethods and the included macro.
-
1
require 'active_support/concern'
-
-
# Defines Class#class_attribute.
-
1
require 'active_support/core_ext/class/attribute'
-
-
# Defines Module#delegate.
-
1
require 'active_support/core_ext/module/delegation'
-
-
# Defines ActiveSupport::Deprecation.
-
1
require 'active_support/deprecation'
-
1
module ActiveSupport
-
# Wrapping a string in this class gives you a prettier way to test
-
# for equality. The value returned by <tt>Rails.env</tt> is wrapped
-
# in a StringInquirer object so instead of calling this:
-
#
-
# Rails.env == 'production'
-
#
-
# you can call this:
-
#
-
# Rails.env.production?
-
1
class StringInquirer < String
-
1
private
-
-
1
def respond_to_missing?(method_name, include_private = false)
-
method_name[-1] == '?'
-
end
-
-
1
def method_missing(method_name, *arguments)
-
5
if method_name[-1] == '?'
-
5
self == method_name[0..-2]
-
else
-
super
-
end
-
end
-
end
-
end
-
1
gem 'minitest' # make sure we get the gem, not stdlib
-
1
require 'minitest/spec'
-
1
require 'active_support/testing/tagged_logging'
-
1
require 'active_support/testing/setup_and_teardown'
-
1
require 'active_support/testing/assertions'
-
1
require 'active_support/testing/deprecation'
-
1
require 'active_support/testing/isolation'
-
1
require 'active_support/testing/mocha_module'
-
1
require 'active_support/testing/constant_lookup'
-
1
require 'active_support/core_ext/kernel/reporting'
-
1
require 'active_support/deprecation'
-
-
1
module ActiveSupport
-
1
class TestCase < ::MiniTest::Spec
-
-
1
include ActiveSupport::Testing::MochaModule
-
-
# Use AS::TestCase for the base class when describing a model
-
1
register_spec_type(self) do |desc|
-
Class === desc && desc < ActiveRecord::Base
-
end
-
-
1
Assertion = MiniTest::Assertion
-
1
alias_method :method_name, :__name__
-
-
1
$tags = {}
-
1
def self.for_tag(tag)
-
yield if $tags[tag]
-
end
-
-
# FIXME: we have tests that depend on run order, we should fix that and
-
# remove this method.
-
1
def self.test_order # :nodoc:
-
526
:sorted
-
end
-
-
1
include ActiveSupport::Testing::TaggedLogging
-
1
include ActiveSupport::Testing::SetupAndTeardown
-
1
include ActiveSupport::Testing::Assertions
-
1
include ActiveSupport::Testing::Deprecation
-
-
1
def self.describe(text)
-
if block_given?
-
super
-
else
-
message = "`describe` without a block is deprecated, please switch to: `def self.name; #{text.inspect}; end`\n"
-
ActiveSupport::Deprecation.warn message
-
-
class_eval <<-RUBY_EVAL, __FILE__, __LINE__ + 1
-
def self.name
-
"#{text}"
-
end
-
RUBY_EVAL
-
end
-
end
-
-
1
class << self
-
1
alias :test :it
-
end
-
-
# test/unit backwards compatibility methods
-
1
alias :assert_raise :assert_raises
-
1
alias :assert_not_nil :refute_nil
-
1
alias :assert_not_equal :refute_equal
-
1
alias :assert_no_match :refute_match
-
1
alias :assert_not_same :refute_same
-
-
# Fails if the block raises an exception.
-
#
-
# assert_nothing_raised do
-
# ...
-
# end
-
1
def assert_nothing_raised(*args)
-
215
yield
-
end
-
end
-
end
-
1
require 'active_support/core_ext/object/blank'
-
-
1
module ActiveSupport
-
1
module Testing
-
1
module Assertions
-
# Test numeric difference between the return value of an expression as a
-
# result of what is evaluated in the yielded block.
-
#
-
# assert_difference 'Article.count' do
-
# post :create, article: {...}
-
# end
-
#
-
# An arbitrary expression is passed in and evaluated.
-
#
-
# assert_difference 'assigns(:article).comments(:reload).size' do
-
# post :create, comment: {...}
-
# end
-
#
-
# An arbitrary positive or negative difference can be specified.
-
# The default is <tt>1</tt>.
-
#
-
# assert_difference 'Article.count', -1 do
-
# post :delete, id: ...
-
# end
-
#
-
# An array of expressions can also be passed in and evaluated.
-
#
-
# assert_difference [ 'Article.count', 'Post.count' ], 2 do
-
# post :create, article: {...}
-
# end
-
#
-
# A lambda or a list of lambdas can be passed in and evaluated:
-
#
-
# assert_difference ->{ Article.count }, 2 do
-
# post :create, article: {...}
-
# end
-
#
-
# assert_difference [->{ Article.count }, ->{ Post.count }], 2 do
-
# post :create, article: {...}
-
# end
-
#
-
# An error message can be specified.
-
#
-
# assert_difference 'Article.count', -1, 'An Article should be destroyed' do
-
# post :delete, id: ...
-
# end
-
1
def assert_difference(expression, difference = 1, message = nil, &block)
-
143
expressions = Array(expression)
-
-
143
exps = expressions.map { |e|
-
465
e.respond_to?(:call) ? e : lambda { eval(e, block.binding) }
-
}
-
299
before = exps.map { |e| e.call }
-
-
143
yield
-
-
142
expressions.zip(exps).each_with_index do |(code, e), i|
-
155
error = "#{code.inspect} didn't change by #{difference}"
-
155
error = "#{message}.\n#{error}" if message
-
155
assert_equal(before[i] + difference, e.call, error)
-
end
-
end
-
-
# Assertion that the numeric result of evaluating an expression is not
-
# changed before and after invoking the passed in block.
-
#
-
# assert_no_difference 'Article.count' do
-
# post :create, article: invalid_attributes
-
# end
-
#
-
# An error message can be specified.
-
#
-
# assert_no_difference 'Article.count', 'An Article should not be created' do
-
# post :create, article: invalid_attributes
-
# end
-
1
def assert_no_difference(expression, message = nil, &block)
-
56
assert_difference expression, 0, message, &block
-
end
-
-
# Test if an expression is blank. Passes if <tt>object.blank?</tt>
-
# is +true+.
-
#
-
# assert_blank [] # => true
-
# assert_blank [[]] # => [[]] is not blank
-
#
-
# An error message can be specified.
-
#
-
# assert_blank [], 'this should be blank'
-
1
def assert_blank(object, message=nil)
-
4
message ||= "#{object.inspect} is not blank"
-
4
assert object.blank?, message
-
end
-
-
# Test if an expression is not blank. Passes if <tt>object.present?</tt>
-
# is +true+.
-
#
-
# assert_present({ data: 'x' }) # => true
-
# assert_present({}) # => {} is blank
-
#
-
# An error message can be specified.
-
#
-
# assert_present({ data: 'x' }, 'this should not be blank')
-
1
def assert_present(object, message=nil)
-
3
message ||= "#{object.inspect} is blank"
-
3
assert object.present?, message
-
end
-
end
-
end
-
end
-
1
require "active_support/concern"
-
1
require "active_support/inflector"
-
-
1
module ActiveSupport
-
1
module Testing
-
# Resolves a constant from a minitest spec name.
-
#
-
# Given the following spec-style test:
-
#
-
# describe WidgetsController, :index do
-
# describe "authenticated user" do
-
# describe "returns widgets" do
-
# it "has a controller that exists" do
-
# assert_kind_of WidgetsController, @controller
-
# end
-
# end
-
# end
-
# end
-
#
-
# The test will have the following name:
-
#
-
# "WidgetsController::index::authenticated user::returns widgets"
-
#
-
# The constant WidgetsController can be resolved from the name.
-
# The following code will resolve the constant:
-
#
-
# controller = determine_constant_from_test_name(name) do |constant|
-
# Class === constant && constant < ::ActionController::Metal
-
# end
-
1
module ConstantLookup
-
1
extend ::ActiveSupport::Concern
-
-
1
module ClassMethods
-
1
def determine_constant_from_test_name(test_name)
-
names = test_name.split "::"
-
while names.size > 0 do
-
names.last.sub!(/Test$/, "")
-
begin
-
constant = names.join("::").constantize
-
break(constant) if yield(constant)
-
rescue NameError
-
# Constant wasn't found, move on
-
ensure
-
names.pop
-
end
-
end
-
end
-
end
-
-
end
-
end
-
end
-
1
require 'active_support/deprecation'
-
-
1
module ActiveSupport
-
1
module Testing
-
1
module Deprecation #:nodoc:
-
1
def assert_deprecated(match = nil, &block)
-
29
result, warnings = collect_deprecations(&block)
-
29
assert !warnings.empty?, "Expected a deprecation warning within the block but received none"
-
29
if match
-
1
match = Regexp.new(Regexp.escape(match)) unless match.is_a?(Regexp)
-
2
assert warnings.any? { |w| w =~ match }, "No deprecation warning matched #{match}: #{warnings.join(', ')}"
-
end
-
29
result
-
end
-
-
1
def assert_not_deprecated(&block)
-
1
result, deprecations = collect_deprecations(&block)
-
1
assert deprecations.empty?, "Expected no deprecation warning within the block but received #{deprecations.size}: \n #{deprecations * "\n "}"
-
1
result
-
end
-
-
1
private
-
1
def collect_deprecations
-
30
old_behavior = ActiveSupport::Deprecation.behavior
-
30
deprecations = []
-
30
ActiveSupport::Deprecation.behavior = Proc.new do |message, callstack|
-
29
deprecations << message
-
end
-
30
result = yield
-
30
[result, deprecations]
-
ensure
-
30
ActiveSupport::Deprecation.behavior = old_behavior
-
end
-
end
-
end
-
end
-
1
require 'rbconfig'
-
1
module ActiveSupport
-
1
module Testing
-
1
class RemoteError < StandardError
-
-
1
attr_reader :message, :backtrace
-
-
1
def initialize(exception)
-
@message = "caught #{exception.class.name}: #{exception.message}"
-
@backtrace = exception.backtrace
-
end
-
end
-
-
1
class ProxyTestResult
-
1
def initialize
-
@calls = []
-
end
-
-
1
def add_error(e)
-
e = Test::Unit::Error.new(e.test_name, RemoteError.new(e.exception))
-
@calls << [:add_error, e]
-
end
-
-
1
def __replay__(result)
-
@calls.each do |name, args|
-
result.send(name, *args)
-
end
-
end
-
-
1
def method_missing(name, *args)
-
@calls << [name, args]
-
end
-
end
-
-
1
module Isolation
-
1
require 'thread'
-
-
1
class ParallelEach
-
1
include Enumerable
-
-
# default to 2 cores
-
1
CORES = (ENV['TEST_CORES'] || 2).to_i
-
-
1
def initialize list
-
@list = list
-
@queue = SizedQueue.new CORES
-
end
-
-
1
def grep pattern
-
self.class.new super
-
end
-
-
1
def each
-
threads = CORES.times.map {
-
Thread.new {
-
while job = @queue.pop
-
yield job
-
end
-
}
-
}
-
@list.each { |i| @queue << i }
-
CORES.times { @queue << nil }
-
threads.each(&:join)
-
end
-
end
-
-
1
def self.included(klass) #:nodoc:
-
klass.extend(Module.new {
-
def test_methods
-
ParallelEach.new super
-
end
-
})
-
end
-
-
1
def self.forking_env?
-
1
!ENV["NO_FORK"] && ((RbConfig::CONFIG['host_os'] !~ /mswin|mingw/) && (RUBY_PLATFORM !~ /java/))
-
end
-
-
1
def _run_class_setup # class setup method should only happen in parent
-
unless defined?(@@ran_class_setup) || ENV['ISOLATION_TEST']
-
self.class.setup if self.class.respond_to?(:setup)
-
@@ran_class_setup = true
-
end
-
end
-
-
1
def run(runner)
-
_run_class_setup
-
-
serialized = run_in_isolation do |isolated_runner|
-
super(isolated_runner)
-
end
-
-
retval, proxy = Marshal.load(serialized)
-
proxy.__replay__(runner)
-
retval
-
end
-
-
1
module Forking
-
1
def run_in_isolation(&blk)
-
read, write = IO.pipe
-
-
pid = fork do
-
read.close
-
proxy = ProxyTestResult.new
-
retval = yield proxy
-
write.puts [Marshal.dump([retval, proxy])].pack("m")
-
exit!
-
end
-
-
write.close
-
result = read.read
-
Process.wait2(pid)
-
return result.unpack("m")[0]
-
end
-
end
-
-
1
module Subprocess
-
1
ORIG_ARGV = ARGV.dup unless defined?(ORIG_ARGV)
-
-
# Crazy H4X to get this working in windows / jruby with
-
# no forking.
-
1
def run_in_isolation(&blk)
-
require "tempfile"
-
-
if ENV["ISOLATION_TEST"]
-
proxy = ProxyTestResult.new
-
retval = yield proxy
-
File.open(ENV["ISOLATION_OUTPUT"], "w") do |file|
-
file.puts [Marshal.dump([retval, proxy])].pack("m")
-
end
-
exit!
-
else
-
Tempfile.open("isolation") do |tmpfile|
-
ENV["ISOLATION_TEST"] = @method_name
-
ENV["ISOLATION_OUTPUT"] = tmpfile.path
-
-
load_paths = $-I.map {|p| "-I\"#{File.expand_path(p)}\"" }.join(" ")
-
`#{Gem.ruby} #{load_paths} #{$0} #{ORIG_ARGV.join(" ")} -t\"#{self.class}\"`
-
-
ENV.delete("ISOLATION_TEST")
-
ENV.delete("ISOLATION_OUTPUT")
-
-
return tmpfile.read.unpack("m")[0]
-
end
-
end
-
end
-
end
-
-
1
include forking_env? ? Forking : Subprocess
-
end
-
end
-
end
-
1
module ActiveSupport
-
1
module Testing
-
1
module MochaModule
-
1
begin
-
1
require 'mocha/api'
-
1
include Mocha::API
-
-
1
def before_setup
-
3640
mocha_setup
-
3640
super
-
end
-
-
1
def after_teardown
-
3640
super
-
3640
mocha_verify
-
3640
mocha_teardown
-
end
-
rescue LoadError
-
end
-
end
-
end
-
end
-
1
require 'active_support/concern'
-
1
require 'active_support/callbacks'
-
-
1
module ActiveSupport
-
1
module Testing
-
1
module SetupAndTeardown
-
1
extend ActiveSupport::Concern
-
-
1
included do
-
1
include ActiveSupport::Callbacks
-
1
define_callbacks :setup, :teardown
-
end
-
-
1
module ClassMethods
-
1
def setup(*args, &block)
-
6
set_callback(:setup, :before, *args, &block)
-
end
-
-
1
def teardown(*args, &block)
-
7
set_callback(:teardown, :after, *args, &block)
-
end
-
end
-
-
1
def before_setup
-
3640
super
-
3640
run_callbacks :setup
-
end
-
-
1
def after_teardown
-
3640
run_callbacks :teardown
-
3640
super
-
end
-
end
-
end
-
end
-
1
module ActiveSupport
-
1
module Testing
-
1
module TaggedLogging
-
1
attr_writer :tagged_logger
-
-
1
def before_setup
-
3640
tagged_logger.push_tags(self.class.name, __name__) if tagged_logging?
-
3640
super
-
end
-
-
1
def after_teardown
-
3640
super
-
3640
tagged_logger.pop_tags(2) if tagged_logging?
-
end
-
-
1
private
-
1
def tagged_logger
-
7280
@tagged_logger ||= (defined?(Rails.logger) && Rails.logger)
-
end
-
-
1
def tagged_logging?
-
7280
tagged_logger && tagged_logger.respond_to?(:push_tags)
-
end
-
end
-
end
-
end
-
1
require 'active_support'
-
-
1
module ActiveSupport
-
1
autoload :Duration, 'active_support/duration'
-
1
autoload :TimeWithZone, 'active_support/time_with_zone'
-
1
autoload :TimeZone, 'active_support/values/time_zone'
-
end
-
-
1
require 'date'
-
1
require 'time'
-
-
1
require 'active_support/core_ext/time/marshal'
-
1
require 'active_support/core_ext/time/acts_like'
-
1
require 'active_support/core_ext/time/calculations'
-
1
require 'active_support/core_ext/time/conversions'
-
1
require 'active_support/core_ext/time/zones'
-
-
1
require 'active_support/core_ext/date/acts_like'
-
1
require 'active_support/core_ext/date/calculations'
-
1
require 'active_support/core_ext/date/conversions'
-
1
require 'active_support/core_ext/date/zones'
-
-
1
require 'active_support/core_ext/date_time/acts_like'
-
1
require 'active_support/core_ext/date_time/calculations'
-
1
require 'active_support/core_ext/date_time/conversions'
-
1
require 'active_support/core_ext/date_time/zones'
-
-
1
require 'active_support/core_ext/integer/time'
-
1
require 'active_support/core_ext/numeric/time'
-
1
require 'active_support/values/time_zone'
-
1
require 'active_support/core_ext/object/acts_like'
-
-
1
module ActiveSupport
-
# A Time-like class that can represent a time in any time zone. Necessary
-
# because standard Ruby Time instances are limited to UTC and the
-
# system's <tt>ENV['TZ']</tt> zone.
-
#
-
# You shouldn't ever need to create a TimeWithZone instance directly via +new+.
-
# Instead use methods +local+, +parse+, +at+ and +now+ on TimeZone instances,
-
# and +in_time_zone+ on Time and DateTime instances.
-
#
-
# Time.zone = 'Eastern Time (US & Canada)' # => 'Eastern Time (US & Canada)'
-
# Time.zone.local(2007, 2, 10, 15, 30, 45) # => Sat, 10 Feb 2007 15:30:45 EST -05:00
-
# Time.zone.parse('2007-02-10 15:30:45') # => Sat, 10 Feb 2007 15:30:45 EST -05:00
-
# Time.zone.at(1170361845) # => Sat, 10 Feb 2007 15:30:45 EST -05:00
-
# Time.zone.now # => Sun, 18 May 2008 13:07:55 EDT -04:00
-
# Time.utc(2007, 2, 10, 20, 30, 45).in_time_zone # => Sat, 10 Feb 2007 15:30:45 EST -05:00
-
#
-
# See Time and TimeZone for further documentation of these methods.
-
#
-
# TimeWithZone instances implement the same API as Ruby Time instances, so
-
# that Time and TimeWithZone instances are interchangeable.
-
#
-
# t = Time.zone.now # => Sun, 18 May 2008 13:27:25 EDT -04:00
-
# t.hour # => 13
-
# t.dst? # => true
-
# t.utc_offset # => -14400
-
# t.zone # => "EDT"
-
# t.to_s(:rfc822) # => "Sun, 18 May 2008 13:27:25 -0400"
-
# t + 1.day # => Mon, 19 May 2008 13:27:25 EDT -04:00
-
# t.beginning_of_year # => Tue, 01 Jan 2008 00:00:00 EST -05:00
-
# t > Time.utc(1999) # => true
-
# t.is_a?(Time) # => true
-
# t.is_a?(ActiveSupport::TimeWithZone) # => true
-
1
class TimeWithZone
-
-
# Report class name as 'Time' to thwart type checking.
-
1
def self.name
-
'Time'
-
end
-
-
1
include Comparable
-
1
attr_reader :time_zone
-
-
1
def initialize(utc_time, time_zone, local_time = nil, period = nil)
-
344
@utc, @time_zone, @time = utc_time, time_zone, local_time
-
344
@period = @utc ? period : get_period_and_ensure_valid_local_time
-
end
-
-
# Returns a Time or DateTime instance that represents the time in +time_zone+.
-
1
def time
-
255
@time ||= period.to_local(@utc)
-
end
-
-
# Returns a Time or DateTime instance that represents the time in UTC.
-
1
def utc
-
163
@utc ||= period.to_utc(@time)
-
end
-
1
alias_method :comparable_time, :utc
-
1
alias_method :getgm, :utc
-
1
alias_method :getutc, :utc
-
1
alias_method :gmtime, :utc
-
-
# Returns the underlying TZInfo::TimezonePeriod.
-
1
def period
-
214
@period ||= time_zone.period_for_utc(@utc)
-
end
-
-
# Returns the simultaneous time in <tt>Time.zone</tt>, or the specified zone.
-
1
def in_time_zone(new_zone = ::Time.zone)
-
59
return self if time_zone == new_zone
-
2
utc.in_time_zone(new_zone)
-
end
-
-
# Returns a <tt>Time.local()</tt> instance of the simultaneous time in your
-
# system's <tt>ENV['TZ']</tt> zone.
-
1
def localtime
-
8
utc.respond_to?(:getlocal) ? utc.getlocal : utc.to_time.getlocal
-
end
-
1
alias_method :getlocal, :localtime
-
-
1
def dst?
-
2
period.dst?
-
end
-
1
alias_method :isdst, :dst?
-
-
1
def utc?
-
47
time_zone.name == 'UTC'
-
end
-
1
alias_method :gmt?, :utc?
-
-
1
def utc_offset
-
47
period.utc_total_offset
-
end
-
1
alias_method :gmt_offset, :utc_offset
-
1
alias_method :gmtoff, :utc_offset
-
-
1
def formatted_offset(colon = true, alternate_utc_string = nil)
-
47
utc? && alternate_utc_string || TimeZone.seconds_to_utc_offset(utc_offset, colon)
-
end
-
-
# Time uses +zone+ to display the time zone abbreviation, so we're
-
# duck-typing it.
-
1
def zone
-
20
period.zone_identifier.to_s
-
end
-
-
1
def inspect
-
18
"#{time.strftime('%a, %d %b %Y %H:%M:%S')} #{zone} #{formatted_offset}"
-
end
-
-
1
def xmlschema(fraction_digits = 0)
-
4
fraction = if fraction_digits > 0
-
(".%06i" % time.usec)[0, fraction_digits + 1]
-
end
-
-
4
"#{time.strftime("%Y-%m-%dT%H:%M:%S")}#{fraction}#{formatted_offset(true, 'Z')}"
-
end
-
1
alias_method :iso8601, :xmlschema
-
-
# Coerces time to a string for JSON encoding. The default format is ISO 8601.
-
# You can get %Y/%m/%d %H:%M:%S +offset style by setting
-
# <tt>ActiveSupport::JSON::Encoding.use_standard_json_time_format</tt>
-
# to +false+.
-
#
-
# # With ActiveSupport::JSON::Encoding.use_standard_json_time_format = true
-
# Time.utc(2005,2,1,15,15,10).in_time_zone.to_json
-
# # => "2005-02-01T15:15:10Z"
-
#
-
# # With ActiveSupport::JSON::Encoding.use_standard_json_time_format = false
-
# Time.utc(2005,2,1,15,15,10).in_time_zone.to_json
-
# # => "2005/02/01 15:15:10 +0000"
-
1
def as_json(options = nil)
-
if ActiveSupport::JSON::Encoding.use_standard_json_time_format
-
xmlschema
-
else
-
%(#{time.strftime("%Y/%m/%d %H:%M:%S")} #{formatted_offset(false)})
-
end
-
end
-
-
1
def encode_with(coder)
-
if coder.respond_to?(:represent_object)
-
coder.represent_object(nil, utc)
-
else
-
coder.represent_scalar(nil, utc.strftime("%Y-%m-%d %H:%M:%S.%9NZ"))
-
end
-
end
-
-
1
def httpdate
-
utc.httpdate
-
end
-
-
1
def rfc2822
-
to_s(:rfc822)
-
end
-
1
alias_method :rfc822, :rfc2822
-
-
# <tt>:db</tt> format outputs time in UTC; all others output time in local.
-
# Uses TimeWithZone's +strftime+, so <tt>%Z</tt> and <tt>%z</tt> work correctly.
-
1
def to_s(format = :default)
-
25
if format == :db
-
utc.to_s(format)
-
25
elsif formatter = ::Time::DATE_FORMATS[format]
-
formatter.respond_to?(:call) ? formatter.call(self).to_s : strftime(formatter)
-
else
-
25
"#{time.strftime("%Y-%m-%d %H:%M:%S")} #{formatted_offset(false, 'UTC')}" # mimicking Ruby 1.9 Time#to_s format
-
end
-
end
-
1
alias_method :to_formatted_s, :to_s
-
-
# Replaces <tt>%Z</tt> and <tt>%z</tt> directives with +zone+ and
-
# +formatted_offset+, respectively, before passing to Time#strftime, so
-
# that zone information is correct
-
1
def strftime(format)
-
format = format.gsub('%Z', zone)
-
.gsub('%z', formatted_offset(false))
-
.gsub('%:z', formatted_offset(true))
-
.gsub('%::z', formatted_offset(true) + ":00")
-
time.strftime(format)
-
end
-
-
# Use the time in UTC for comparisons.
-
1
def <=>(other)
-
65
utc <=> other
-
end
-
-
1
def between?(min, max)
-
utc.between?(min, max)
-
end
-
-
1
def past?
-
utc.past?
-
end
-
-
1
def today?
-
time.today?
-
end
-
-
1
def future?
-
utc.future?
-
end
-
-
1
def eql?(other)
-
utc.eql?(other)
-
end
-
-
1
def hash
-
utc.hash
-
end
-
-
1
def +(other)
-
# If we're adding a Duration of variable length (i.e., years, months, days), move forward from #time,
-
# otherwise move forward from #utc, for accuracy when moving across DST boundaries
-
if duration_of_variable_length?(other)
-
method_missing(:+, other)
-
else
-
result = utc.acts_like?(:date) ? utc.since(other) : utc + other rescue utc.since(other)
-
result.in_time_zone(time_zone)
-
end
-
end
-
-
1
def -(other)
-
# If we're subtracting a Duration of variable length (i.e., years, months, days), move backwards from #time,
-
# otherwise move backwards #utc, for accuracy when moving across DST boundaries
-
if other.acts_like?(:time)
-
utc.to_f - other.to_f
-
elsif duration_of_variable_length?(other)
-
method_missing(:-, other)
-
else
-
result = utc.acts_like?(:date) ? utc.ago(other) : utc - other rescue utc.ago(other)
-
result.in_time_zone(time_zone)
-
end
-
end
-
-
1
def since(other)
-
# If we're adding a Duration of variable length (i.e., years, months, days), move forward from #time,
-
# otherwise move forward from #utc, for accuracy when moving across DST boundaries
-
if duration_of_variable_length?(other)
-
method_missing(:since, other)
-
else
-
utc.since(other).in_time_zone(time_zone)
-
end
-
end
-
-
1
def ago(other)
-
since(-other)
-
end
-
-
1
def advance(options)
-
# If we're advancing a value of variable length (i.e., years, weeks, months, days), advance from #time,
-
# otherwise advance from #utc, for accuracy when moving across DST boundaries
-
if options.values_at(:years, :weeks, :months, :days).any?
-
method_missing(:advance, options)
-
else
-
utc.advance(options).in_time_zone(time_zone)
-
end
-
end
-
-
1
%w(year mon month day mday wday yday hour min sec to_date).each do |method_name|
-
11
class_eval <<-EOV, __FILE__, __LINE__ + 1
-
def #{method_name} # def month
-
time.#{method_name} # time.month
-
end # end
-
EOV
-
end
-
-
1
def usec
-
20
time.respond_to?(:usec) ? time.usec : 0
-
end
-
-
1
def to_a
-
2
[time.sec, time.min, time.hour, time.day, time.mon, time.year, time.wday, time.yday, dst?, zone]
-
end
-
-
1
def to_f
-
utc.to_f
-
end
-
-
1
def to_i
-
utc.to_i
-
end
-
1
alias_method :tv_sec, :to_i
-
-
# A TimeWithZone acts like a Time, so just return +self+.
-
1
def to_time
-
66
utc
-
end
-
-
1
def to_datetime
-
utc.to_datetime.new_offset(Rational(utc_offset, 86_400))
-
end
-
-
# So that +self+ <tt>acts_like?(:time)</tt>.
-
1
def acts_like_time?
-
true
-
end
-
-
# Say we're a Time to thwart type checking.
-
1
def is_a?(klass)
-
145
klass == ::Time || super
-
end
-
1
alias_method :kind_of?, :is_a?
-
-
1
def freeze
-
period; utc; time # preload instance variables before freezing
-
super
-
end
-
-
1
def marshal_dump
-
[utc, time_zone.name, time]
-
end
-
-
1
def marshal_load(variables)
-
initialize(variables[0].utc, ::Time.find_zone(variables[1]), variables[2].utc)
-
end
-
-
# Ensure proxy class responds to all methods that underlying time instance
-
# responds to.
-
1
def respond_to_missing?(sym, include_priv)
-
# consistently respond false to acts_like?(:date), regardless of whether #time is a Time or DateTime
-
30
return false if sym.to_sym == :acts_like_date?
-
30
time.respond_to?(sym, include_priv)
-
end
-
-
# Send the missing method to +time+ instance, and wrap result in a new
-
# TimeWithZone with the existing +time_zone+.
-
1
def method_missing(sym, *args, &block)
-
66
wrap_with_time_zone time.__send__(sym, *args, &block)
-
end
-
-
1
private
-
1
def get_period_and_ensure_valid_local_time
-
# we don't want a Time.local instance enforcing its own DST rules as well,
-
# so transfer time values to a utc constructor if necessary
-
126
@time = transfer_time_values_to_utc_constructor(@time) unless @time.utc?
-
126
begin
-
126
@time_zone.period_for_local(@time)
-
rescue ::TZInfo::PeriodNotFound
-
# time is in the "spring forward" hour gap, so we're moving the time forward one hour and trying again
-
@time += 1.hour
-
retry
-
end
-
end
-
-
1
def transfer_time_values_to_utc_constructor(time)
-
56
::Time.utc_time(time.year, time.month, time.day, time.hour, time.min, time.sec, time.respond_to?(:nsec) ? Rational(time.nsec, 1000) : 0)
-
end
-
-
1
def duration_of_variable_length?(obj)
-
ActiveSupport::Duration === obj && obj.parts.any? {|p| [:years, :months, :days].include?(p[0]) }
-
end
-
-
1
def wrap_with_time_zone(time)
-
66
if time.acts_like?(:time)
-
66
self.class.new(nil, time_zone, time)
-
elsif time.is_a?(Range)
-
wrap_with_time_zone(time.begin)..wrap_with_time_zone(time.end)
-
else
-
time
-
end
-
end
-
end
-
end
-
1
require 'active_support/core_ext/object/blank'
-
1
require 'active_support/core_ext/object/try'
-
-
1
module ActiveSupport
-
# The TimeZone class serves as a wrapper around TZInfo::Timezone instances.
-
# It allows us to do the following:
-
#
-
# * Limit the set of zones provided by TZInfo to a meaningful subset of 142
-
# zones.
-
# * Retrieve and display zones with a friendlier name
-
# (e.g., "Eastern Time (US & Canada)" instead of "America/New_York").
-
# * Lazily load TZInfo::Timezone instances only when they're needed.
-
# * Create ActiveSupport::TimeWithZone instances via TimeZone's +local+,
-
# +parse+, +at+ and +now+ methods.
-
#
-
# If you set <tt>config.time_zone</tt> in the Rails Application, you can
-
# access this TimeZone object via <tt>Time.zone</tt>:
-
#
-
# # application.rb:
-
# class Application < Rails::Application
-
# config.time_zone = 'Eastern Time (US & Canada)'
-
# end
-
#
-
# Time.zone # => #<TimeZone:0x514834...>
-
# Time.zone.name # => "Eastern Time (US & Canada)"
-
# Time.zone.now # => Sun, 18 May 2008 14:30:44 EDT -04:00
-
#
-
# The version of TZInfo bundled with Active Support only includes the
-
# definitions necessary to support the zones defined by the TimeZone class.
-
# If you need to use zones that aren't defined by TimeZone, you'll need to
-
# install the TZInfo gem (if a recent version of the gem is installed locally,
-
# this will be used instead of the bundled version.)
-
1
class TimeZone
-
# Keys are Rails TimeZone names, values are TZInfo identifiers.
-
1
MAPPING = {
-
"International Date Line West" => "Pacific/Midway",
-
"Midway Island" => "Pacific/Midway",
-
"American Samoa" => "Pacific/Pago_Pago",
-
"Hawaii" => "Pacific/Honolulu",
-
"Alaska" => "America/Juneau",
-
"Pacific Time (US & Canada)" => "America/Los_Angeles",
-
"Tijuana" => "America/Tijuana",
-
"Mountain Time (US & Canada)" => "America/Denver",
-
"Arizona" => "America/Phoenix",
-
"Chihuahua" => "America/Chihuahua",
-
"Mazatlan" => "America/Mazatlan",
-
"Central Time (US & Canada)" => "America/Chicago",
-
"Saskatchewan" => "America/Regina",
-
"Guadalajara" => "America/Mexico_City",
-
"Mexico City" => "America/Mexico_City",
-
"Monterrey" => "America/Monterrey",
-
"Central America" => "America/Guatemala",
-
"Eastern Time (US & Canada)" => "America/New_York",
-
"Indiana (East)" => "America/Indiana/Indianapolis",
-
"Bogota" => "America/Bogota",
-
"Lima" => "America/Lima",
-
"Quito" => "America/Lima",
-
"Atlantic Time (Canada)" => "America/Halifax",
-
"Caracas" => "America/Caracas",
-
"La Paz" => "America/La_Paz",
-
"Santiago" => "America/Santiago",
-
"Newfoundland" => "America/St_Johns",
-
"Brasilia" => "America/Sao_Paulo",
-
"Buenos Aires" => "America/Argentina/Buenos_Aires",
-
"Georgetown" => "America/Guyana",
-
"Greenland" => "America/Godthab",
-
"Mid-Atlantic" => "Atlantic/South_Georgia",
-
"Azores" => "Atlantic/Azores",
-
"Cape Verde Is." => "Atlantic/Cape_Verde",
-
"Dublin" => "Europe/Dublin",
-
"Edinburgh" => "Europe/London",
-
"Lisbon" => "Europe/Lisbon",
-
"London" => "Europe/London",
-
"Casablanca" => "Africa/Casablanca",
-
"Monrovia" => "Africa/Monrovia",
-
"UTC" => "Etc/UTC",
-
"Belgrade" => "Europe/Belgrade",
-
"Bratislava" => "Europe/Bratislava",
-
"Budapest" => "Europe/Budapest",
-
"Ljubljana" => "Europe/Ljubljana",
-
"Prague" => "Europe/Prague",
-
"Sarajevo" => "Europe/Sarajevo",
-
"Skopje" => "Europe/Skopje",
-
"Warsaw" => "Europe/Warsaw",
-
"Zagreb" => "Europe/Zagreb",
-
"Brussels" => "Europe/Brussels",
-
"Copenhagen" => "Europe/Copenhagen",
-
"Madrid" => "Europe/Madrid",
-
"Paris" => "Europe/Paris",
-
"Amsterdam" => "Europe/Amsterdam",
-
"Berlin" => "Europe/Berlin",
-
"Bern" => "Europe/Berlin",
-
"Rome" => "Europe/Rome",
-
"Stockholm" => "Europe/Stockholm",
-
"Vienna" => "Europe/Vienna",
-
"West Central Africa" => "Africa/Algiers",
-
"Bucharest" => "Europe/Bucharest",
-
"Cairo" => "Africa/Cairo",
-
"Helsinki" => "Europe/Helsinki",
-
"Kyiv" => "Europe/Kiev",
-
"Riga" => "Europe/Riga",
-
"Sofia" => "Europe/Sofia",
-
"Tallinn" => "Europe/Tallinn",
-
"Vilnius" => "Europe/Vilnius",
-
"Athens" => "Europe/Athens",
-
"Istanbul" => "Europe/Istanbul",
-
"Minsk" => "Europe/Minsk",
-
"Jerusalem" => "Asia/Jerusalem",
-
"Harare" => "Africa/Harare",
-
"Pretoria" => "Africa/Johannesburg",
-
"Moscow" => "Europe/Moscow",
-
"St. Petersburg" => "Europe/Moscow",
-
"Volgograd" => "Europe/Moscow",
-
"Kuwait" => "Asia/Kuwait",
-
"Riyadh" => "Asia/Riyadh",
-
"Nairobi" => "Africa/Nairobi",
-
"Baghdad" => "Asia/Baghdad",
-
"Tehran" => "Asia/Tehran",
-
"Abu Dhabi" => "Asia/Muscat",
-
"Muscat" => "Asia/Muscat",
-
"Baku" => "Asia/Baku",
-
"Tbilisi" => "Asia/Tbilisi",
-
"Yerevan" => "Asia/Yerevan",
-
"Kabul" => "Asia/Kabul",
-
"Ekaterinburg" => "Asia/Yekaterinburg",
-
"Islamabad" => "Asia/Karachi",
-
"Karachi" => "Asia/Karachi",
-
"Tashkent" => "Asia/Tashkent",
-
"Chennai" => "Asia/Kolkata",
-
"Kolkata" => "Asia/Kolkata",
-
"Mumbai" => "Asia/Kolkata",
-
"New Delhi" => "Asia/Kolkata",
-
"Kathmandu" => "Asia/Kathmandu",
-
"Astana" => "Asia/Dhaka",
-
"Dhaka" => "Asia/Dhaka",
-
"Sri Jayawardenepura" => "Asia/Colombo",
-
"Almaty" => "Asia/Almaty",
-
"Novosibirsk" => "Asia/Novosibirsk",
-
"Rangoon" => "Asia/Rangoon",
-
"Bangkok" => "Asia/Bangkok",
-
"Hanoi" => "Asia/Bangkok",
-
"Jakarta" => "Asia/Jakarta",
-
"Krasnoyarsk" => "Asia/Krasnoyarsk",
-
"Beijing" => "Asia/Shanghai",
-
"Chongqing" => "Asia/Chongqing",
-
"Hong Kong" => "Asia/Hong_Kong",
-
"Urumqi" => "Asia/Urumqi",
-
"Kuala Lumpur" => "Asia/Kuala_Lumpur",
-
"Singapore" => "Asia/Singapore",
-
"Taipei" => "Asia/Taipei",
-
"Perth" => "Australia/Perth",
-
"Irkutsk" => "Asia/Irkutsk",
-
"Ulaan Bataar" => "Asia/Ulaanbaatar",
-
"Seoul" => "Asia/Seoul",
-
"Osaka" => "Asia/Tokyo",
-
"Sapporo" => "Asia/Tokyo",
-
"Tokyo" => "Asia/Tokyo",
-
"Yakutsk" => "Asia/Yakutsk",
-
"Darwin" => "Australia/Darwin",
-
"Adelaide" => "Australia/Adelaide",
-
"Canberra" => "Australia/Melbourne",
-
"Melbourne" => "Australia/Melbourne",
-
"Sydney" => "Australia/Sydney",
-
"Brisbane" => "Australia/Brisbane",
-
"Hobart" => "Australia/Hobart",
-
"Vladivostok" => "Asia/Vladivostok",
-
"Guam" => "Pacific/Guam",
-
"Port Moresby" => "Pacific/Port_Moresby",
-
"Magadan" => "Asia/Magadan",
-
"Solomon Is." => "Pacific/Guadalcanal",
-
"New Caledonia" => "Pacific/Noumea",
-
"Fiji" => "Pacific/Fiji",
-
"Kamchatka" => "Asia/Kamchatka",
-
"Marshall Is." => "Pacific/Majuro",
-
"Auckland" => "Pacific/Auckland",
-
"Wellington" => "Pacific/Auckland",
-
"Nuku'alofa" => "Pacific/Tongatapu",
-
"Tokelau Is." => "Pacific/Fakaofo",
-
"Samoa" => "Pacific/Apia"
-
}
-
-
1
UTC_OFFSET_WITH_COLON = '%s%02d:%02d'
-
1
UTC_OFFSET_WITHOUT_COLON = UTC_OFFSET_WITH_COLON.sub(':', '')
-
-
# Assumes self represents an offset from UTC in seconds (as returned from
-
# Time#utc_offset) and turns this into an +HH:MM formatted string.
-
#
-
# TimeZone.seconds_to_utc_offset(-21_600) # => "-06:00"
-
1
def self.seconds_to_utc_offset(seconds, colon = true)
-
48
format = colon ? UTC_OFFSET_WITH_COLON : UTC_OFFSET_WITHOUT_COLON
-
48
sign = (seconds < 0 ? '-' : '+')
-
48
hours = seconds.abs / 3600
-
48
minutes = (seconds.abs % 3600) / 60
-
48
format % [sign, hours, minutes]
-
end
-
-
1
include Comparable
-
1
attr_reader :name
-
1
attr_reader :tzinfo
-
-
# Create a new TimeZone object with the given name and offset. The
-
# offset is the number of seconds that this time zone is offset from UTC
-
# (GMT). Seconds were chosen as the offset unit because that is the unit
-
# that Ruby uses to represent time zone offsets (see Time#utc_offset).
-
1
def initialize(name, utc_offset = nil, tzinfo = nil)
-
147
self.class.send(:require_tzinfo)
-
-
147
@name = name
-
147
@utc_offset = utc_offset
-
147
@tzinfo = tzinfo || TimeZone.find_tzinfo(name)
-
147
@current_period = nil
-
end
-
-
# Returns the offset of this time zone from UTC in seconds.
-
1
def utc_offset
-
6289
if @utc_offset
-
@utc_offset
-
else
-
6289
@current_period ||= tzinfo.try(:current_period)
-
6289
@current_period.try(:utc_offset)
-
end
-
end
-
-
# Returns the offset of this time zone as a formatted string, of the
-
# format "+HH:MM".
-
1
def formatted_offset(colon=true, alternate_utc_string = nil)
-
utc_offset == 0 && alternate_utc_string || self.class.seconds_to_utc_offset(utc_offset, colon)
-
end
-
-
# Compare this time zone to the parameter. The two are compared first on
-
# their offsets, and then by name.
-
1
def <=>(zone)
-
828
result = (utc_offset <=> zone.utc_offset)
-
828
result = (name <=> zone.name) if result == 0
-
828
result
-
end
-
-
# Compare #name and TZInfo identifier to a supplied regexp, returning +true+
-
# if a match is found.
-
1
def =~(re)
-
return true if name =~ re || MAPPING[name] =~ re
-
end
-
-
# Returns a textual representation of this time zone.
-
1
def to_s
-
"(GMT#{formatted_offset}) #{name}"
-
end
-
-
# Method for creating new ActiveSupport::TimeWithZone instance in time zone
-
# of +self+ from given values.
-
#
-
# Time.zone = 'Hawaii' # => "Hawaii"
-
# Time.zone.local(2007, 2, 1, 15, 30, 45) # => Thu, 01 Feb 2007 15:30:45 HST -10:00
-
1
def local(*args)
-
4
time = Time.utc_time(*args)
-
4
ActiveSupport::TimeWithZone.new(nil, self, time)
-
end
-
-
# Method for creating new ActiveSupport::TimeWithZone instance in time zone
-
# of +self+ from number of seconds since the Unix epoch.
-
#
-
# Time.zone = 'Hawaii' # => "Hawaii"
-
# Time.utc(2000).to_f # => 946684800.0
-
# Time.zone.at(946684800.0) # => Fri, 31 Dec 1999 14:00:00 HST -10:00
-
1
def at(secs)
-
Time.at(secs).utc.in_time_zone(self)
-
end
-
-
# Method for creating new ActiveSupport::TimeWithZone instance in time zone
-
# of +self+ from parsed string.
-
#
-
# Time.zone = 'Hawaii' # => "Hawaii"
-
# Time.zone.parse('1999-12-31 14:00:00') # => Fri, 31 Dec 1999 14:00:00 HST -10:00
-
#
-
# If upper components are missing from the string, they are supplied from
-
# TimeZone#now:
-
#
-
# Time.zone.now # => Fri, 31 Dec 1999 14:00:00 HST -10:00
-
# Time.zone.parse('22:30:00') # => Fri, 31 Dec 1999 22:30:00 HST -10:00
-
1
def parse(str, now=now)
-
108
date_parts = Date._parse(str)
-
108
return if date_parts.empty?
-
106
time = Time.parse(str, now) rescue DateTime.parse(str)
-
-
106
if date_parts[:offset].nil?
-
56
if date_parts[:hour] && time.hour != date_parts[:hour]
-
time = DateTime.parse(str)
-
end
-
-
56
ActiveSupport::TimeWithZone.new(nil, self, time)
-
else
-
50
time.in_time_zone(self)
-
end
-
end
-
-
# Returns an ActiveSupport::TimeWithZone instance representing the current
-
# time in the time zone represented by +self+.
-
#
-
# Time.zone = 'Hawaii' # => "Hawaii"
-
# Time.zone.now # => Wed, 23 Jan 2008 20:24:27 HST -10:00
-
1
def now
-
108
time_now.utc.in_time_zone(self)
-
end
-
-
# Return the current date in this time zone.
-
1
def today
-
tzinfo.now.to_date
-
end
-
-
# Adjust the given time to the simultaneous time in the time zone
-
# represented by +self+. Returns a Time.utc() instance -- if you want an
-
# ActiveSupport::TimeWithZone instance, use Time#in_time_zone() instead.
-
1
def utc_to_local(time)
-
tzinfo.utc_to_local(time)
-
end
-
-
# Adjust the given time to the simultaneous time in UTC. Returns a
-
# Time.utc() instance.
-
1
def local_to_utc(time, dst=true)
-
tzinfo.local_to_utc(time, dst)
-
end
-
-
# Available so that TimeZone instances respond like TZInfo::Timezone
-
# instances.
-
1
def period_for_utc(time)
-
77
tzinfo.period_for_utc(time)
-
end
-
-
# Available so that TimeZone instances respond like TZInfo::Timezone
-
# instances.
-
1
def period_for_local(time, dst=true)
-
126
tzinfo.period_for_local(time, dst)
-
end
-
-
1
def self.find_tzinfo(name)
-
148
TZInfo::TimezoneProxy.new(MAPPING[name] || name)
-
end
-
-
1
class << self
-
1
alias_method :create, :new
-
-
# Return a TimeZone instance with the given name, or +nil+ if no
-
# such TimeZone instance exists. (This exists to support the use of
-
# this class with the +composed_of+ macro.)
-
1
def new(name)
-
self[name]
-
end
-
-
# Return an array of all TimeZone objects. There are multiple
-
# TimeZone objects per time zone, in many cases, to make it easier
-
# for users to find their own time zone.
-
1
def all
-
80
@zones ||= zones_map.values.sort
-
end
-
-
1
def zones_map
-
@zones_map ||= begin
-
1
new_zones_names = MAPPING.keys - lazy_zones_map.keys
-
143
new_zones = Hash[new_zones_names.map { |place| [place, create(place)] }]
-
-
1
lazy_zones_map.merge(new_zones)
-
1
end
-
end
-
-
# Locate a specific time zone object. If the argument is a string, it
-
# is interpreted to mean the name of the timezone to locate. If it is a
-
# numeric value it is either the hour offset, or the second offset, of the
-
# timezone to find. (The first one with that offset will be returned.)
-
# Returns +nil+ if no such time zone is known to the system.
-
1
def [](arg)
-
160
case arg
-
when String
-
80
begin
-
81
lazy_zones_map[arg] ||= lookup(arg).tap { |tz| tz.utc_offset }
-
rescue TZInfo::InvalidTimezoneIdentifier
-
nil
-
end
-
when Numeric, ActiveSupport::Duration
-
80
arg *= 3600 if arg.abs <= 13
-
4712
all.find { |z| z.utc_offset == arg.to_i }
-
else
-
raise ArgumentError, "invalid argument to TimeZone[]: #{arg.inspect}"
-
end
-
end
-
-
# A convenience method for returning a collection of TimeZone objects
-
# for time zones in the USA.
-
1
def us_zones
-
@us_zones ||= all.find_all { |z| z.name =~ /US|Arizona|Indiana|Hawaii|Alaska/ }
-
end
-
-
1
protected
-
-
1
def require_tzinfo
-
229
require 'tzinfo' unless defined?(::TZInfo)
-
rescue LoadError
-
$stderr.puts "You don't have tzinfo installed in your application. Please add it to your Gemfile and run bundle install"
-
raise
-
end
-
-
1
private
-
-
1
def lookup(name)
-
1
(tzinfo = find_tzinfo(name)) && create(tzinfo.name.freeze)
-
end
-
-
1
def lazy_zones_map
-
82
require_tzinfo
-
-
@lazy_zones_map ||= Hash.new do |hash, place|
-
5
hash[place] = create(place) if MAPPING.has_key?(place)
-
82
end
-
end
-
end
-
-
1
private
-
-
1
def time_now
-
108
Time.now
-
end
-
end
-
end
-
1
module ActiveSupport
-
1
module VERSION #:nodoc:
-
1
MAJOR = 4
-
1
MINOR = 0
-
1
TINY = 0
-
1
PRE = "beta"
-
-
1
STRING = [MAJOR, MINOR, TINY, PRE].compact.join('.')
-
end
-
end
-
1
require 'time'
-
1
require 'base64'
-
1
require 'active_support/core_ext/module/delegation'
-
1
require 'active_support/core_ext/string/inflections'
-
-
1
module ActiveSupport
-
# = XmlMini
-
#
-
# To use the much faster libxml parser:
-
# gem 'libxml-ruby', '=0.9.7'
-
# XmlMini.backend = 'LibXML'
-
1
module XmlMini
-
1
extend self
-
-
# This module decorates files deserialized using Hash.from_xml with
-
# the <tt>original_filename</tt> and <tt>content_type</tt> methods.
-
1
module FileLike #:nodoc:
-
1
attr_writer :original_filename, :content_type
-
-
1
def original_filename
-
@original_filename || 'untitled'
-
end
-
-
1
def content_type
-
@content_type || 'application/octet-stream'
-
end
-
end
-
-
DEFAULT_ENCODINGS = {
-
"binary" => "base64"
-
1
} unless defined?(DEFAULT_ENCODINGS)
-
-
TYPE_NAMES = {
-
"Symbol" => "symbol",
-
"Fixnum" => "integer",
-
"Bignum" => "integer",
-
"BigDecimal" => "decimal",
-
"Float" => "float",
-
"TrueClass" => "boolean",
-
"FalseClass" => "boolean",
-
"Date" => "date",
-
"DateTime" => "dateTime",
-
"Time" => "dateTime",
-
"Array" => "array",
-
"Hash" => "hash"
-
1
} unless defined?(TYPE_NAMES)
-
-
FORMATTING = {
-
"symbol" => Proc.new { |symbol| symbol.to_s },
-
6
"date" => Proc.new { |date| date.to_s(:db) },
-
50
"dateTime" => Proc.new { |time| time.xmlschema },
-
10
"binary" => Proc.new { |binary| ::Base64.encode64(binary) },
-
"yaml" => Proc.new { |yaml| yaml.to_yaml }
-
1
} unless defined?(FORMATTING)
-
-
# TODO use regexp instead of Date.parse
-
1
unless defined?(PARSING)
-
1
PARSING = {
-
"symbol" => Proc.new { |symbol| symbol.to_sym },
-
"date" => Proc.new { |date| ::Date.parse(date) },
-
1
"datetime" => Proc.new { |time| Time.xmlschema(time).utc rescue ::DateTime.parse(time).utc },
-
103
"integer" => Proc.new { |integer| integer.to_i },
-
"float" => Proc.new { |float| float.to_f },
-
"decimal" => Proc.new { |number| BigDecimal(number) },
-
1
"boolean" => Proc.new { |boolean| %w(1 true).include?(boolean.strip) },
-
"string" => Proc.new { |string| string.to_s },
-
"yaml" => Proc.new { |yaml| YAML::load(yaml) rescue yaml },
-
"base64Binary" => Proc.new { |bin| ::Base64.decode64(bin) },
-
1
"binary" => Proc.new { |bin, entity| _parse_binary(bin, entity) },
-
"file" => Proc.new { |file, entity| _parse_file(file, entity) }
-
}
-
-
1
PARSING.update(
-
"double" => PARSING["float"],
-
"dateTime" => PARSING["datetime"]
-
)
-
end
-
-
1
attr_reader :backend
-
1
delegate :parse, :to => :backend
-
-
1
def backend=(name)
-
1
if name.is_a?(Module)
-
@backend = name
-
else
-
1
require "active_support/xml_mini/#{name.downcase}"
-
1
@backend = ActiveSupport.const_get("XmlMini_#{name}")
-
end
-
end
-
-
1
def with_backend(name)
-
old_backend, self.backend = backend, name
-
yield
-
ensure
-
self.backend = old_backend
-
end
-
-
1
def to_tag(key, value, options)
-
1032
type_name = options.delete(:type)
-
1032
merged_options = options.merge(:root => key, :skip_instruct => true)
-
-
1032
if value.is_a?(::Method) || value.is_a?(::Proc)
-
if value.arity == 1
-
value.call(merged_options)
-
else
-
value.call(merged_options, key.to_s.singularize)
-
end
-
1032
elsif value.respond_to?(:to_xml)
-
25
value.to_xml(merged_options)
-
else
-
1007
type_name ||= TYPE_NAMES[value.class.name]
-
1007
type_name ||= value.class.name if value && !value.respond_to?(:to_str)
-
1007
type_name = type_name.to_s if type_name
-
1007
type_name = "dateTime" if type_name == "datetime"
-
-
1007
key = rename_key(key.to_s, options)
-
-
1007
attributes = options[:skip_types] || type_name.nil? ? { } : { :type => type_name }
-
1007
attributes[:nil] = true if value.nil?
-
-
1007
encoding = options[:encoding] || DEFAULT_ENCODINGS[type_name]
-
1007
attributes[:encoding] = encoding if encoding
-
-
1007
formatted_value = FORMATTING[type_name] && !value.nil? ?
-
FORMATTING[type_name].call(value) : value
-
-
1007
options[:builder].tag!(key, formatted_value, attributes)
-
end
-
end
-
-
1
def rename_key(key, options = {})
-
2163
camelize = options[:camelize]
-
2163
dasherize = !options.has_key?(:dasherize) || options[:dasherize]
-
2163
if camelize
-
17
key = true == camelize ? key.camelize : key.camelize(camelize)
-
end
-
2163
key = _dasherize(key) if dasherize
-
2163
key
-
end
-
-
1
protected
-
-
1
def _dasherize(key)
-
# $2 must be a non-greedy regex for this to work
-
2146
left, middle, right = /\A(_*)(.*?)(_*)\Z/.match(key.strip)[1,3]
-
2146
"#{left}#{middle.tr('_ ', '--')}#{right}"
-
end
-
-
# TODO: Add support for other encodings
-
1
def _parse_binary(bin, entity) #:nodoc:
-
1
case entity['encoding']
-
when 'base64'
-
1
::Base64.decode64(bin)
-
else
-
bin
-
end
-
end
-
-
1
def _parse_file(file, entity)
-
f = StringIO.new(::Base64.decode64(file))
-
f.extend(FileLike)
-
f.original_filename = entity['name']
-
f.content_type = entity['content_type']
-
f
-
end
-
end
-
-
1
XmlMini.backend = 'REXML'
-
end
-
1
require 'active_support/core_ext/kernel/reporting'
-
1
require 'active_support/core_ext/object/blank'
-
1
require 'stringio'
-
-
1
module ActiveSupport
-
1
module XmlMini_REXML #:nodoc:
-
1
extend self
-
-
1
CONTENT_KEY = '__content__'.freeze
-
-
# Parse an XML Document string or IO into a simple hash.
-
#
-
# Same as XmlSimple::xml_in but doesn't shoot itself in the foot,
-
# and uses the defaults from Active Support.
-
#
-
# data::
-
# XML Document string or IO to parse
-
1
def parse(data)
-
8
if !data.respond_to?(:read)
-
8
data = StringIO.new(data || '')
-
end
-
-
8
char = data.getc
-
8
if char.nil?
-
{}
-
else
-
8
data.ungetc(char)
-
8
silence_warnings { require 'rexml/document' } unless defined?(REXML::Document)
-
8
doc = REXML::Document.new(data)
-
-
8
if doc.root
-
8
merge_element!({}, doc.root)
-
else
-
raise REXML::ParseException,
-
"The document #{doc.to_s.inspect} does not have a valid root"
-
end
-
end
-
end
-
-
1
private
-
# Convert an XML element and merge into the hash
-
#
-
# hash::
-
# Hash to merge the converted element into.
-
# element::
-
# XML element to merge into hash
-
1
def merge_element!(hash, element)
-
184
merge!(hash, element.name, collapse(element))
-
end
-
-
# Actually converts an XML document element into a data structure.
-
#
-
# element::
-
# The document element to be collapsed.
-
1
def collapse(element)
-
184
hash = get_attributes(element)
-
-
184
if element.has_elements?
-
201
element.each_element {|child| merge_element!(hash, child) }
-
25
merge_texts!(hash, element) unless empty_content?(element)
-
25
hash
-
else
-
159
merge_texts!(hash, element)
-
end
-
end
-
-
# Merge all the texts of an element into the hash
-
#
-
# hash::
-
# Hash to add the converted element to.
-
# element::
-
# XML element whose texts are to me merged into the hash
-
1
def merge_texts!(hash, element)
-
159
unless element.has_text?
-
14
hash
-
else
-
# must use value to prevent double-escaping
-
145
texts = ''
-
290
element.texts.each { |t| texts << t.value }
-
145
merge!(hash, CONTENT_KEY, texts)
-
end
-
end
-
-
# Adds a new key/value pair to an existing Hash. If the key to be added
-
# already exists and the existing value associated with key is not
-
# an Array, it will be wrapped in an Array. Then the new value is
-
# appended to that Array.
-
#
-
# hash::
-
# Hash to add key/value pair to.
-
# key::
-
# Key to be added.
-
# value::
-
# Value to be associated with key.
-
1
def merge!(hash, key, value)
-
329
if hash.has_key?(key)
-
11
if hash[key].instance_of?(Array)
-
7
hash[key] << value
-
else
-
4
hash[key] = [hash[key], value]
-
end
-
elsif value.instance_of?(Array)
-
hash[key] = [value]
-
else
-
318
hash[key] = value
-
end
-
329
hash
-
end
-
-
# Converts the attributes array of an XML element into a hash.
-
# Returns an empty Hash if node has no attributes.
-
#
-
# element::
-
# XML element to extract attributes from.
-
1
def get_attributes(element)
-
184
attributes = {}
-
334
element.attributes.each { |n,v| attributes[n] = v }
-
184
attributes
-
end
-
-
# Determines if a document element has text content
-
#
-
# element::
-
# XML element to be checked.
-
1
def empty_content?(element)
-
25
element.texts.join.blank?
-
end
-
end
-
end
-
# bust gem prelude
-
1
require 'bundler'
-
1
Bundler.setup
-
# A wrapper for OpenBSD's bcrypt/crypt_blowfish password-hashing algorithm.
-
-
1
if RUBY_PLATFORM == "java"
-
require 'java'
-
else
-
1
require "openssl"
-
end
-
-
1
if defined?(RUBY_ENGINE) and RUBY_ENGINE == "maglev"
-
require 'bcrypt_engine'
-
else
-
1
require 'bcrypt_ext'
-
end
-
-
# A Ruby library implementing OpenBSD's bcrypt()/crypt_blowfish algorithm for
-
# hashing passwords.
-
1
module BCrypt
-
1
module Errors
-
1
class InvalidSalt < StandardError; end # The salt parameter provided to bcrypt() is invalid.
-
1
class InvalidHash < StandardError; end # The hash parameter provided to bcrypt() is invalid.
-
1
class InvalidCost < StandardError; end # The cost parameter provided to bcrypt() is invalid.
-
1
class InvalidSecret < StandardError; end # The secret parameter provided to bcrypt() is invalid.
-
end
-
-
# A Ruby wrapper for the bcrypt() C extension calls and the Java calls.
-
1
class Engine
-
# The default computational expense parameter.
-
1
DEFAULT_COST = 10
-
# The minimum cost supported by the algorithm.
-
1
MIN_COST = 4
-
# Maximum possible size of bcrypt() salts.
-
1
MAX_SALT_LENGTH = 16
-
-
1
if RUBY_PLATFORM != "java"
-
# C-level routines which, if they don't get the right input, will crash the
-
# hell out of the Ruby process.
-
1
private_class_method :__bc_salt
-
1
private_class_method :__bc_crypt
-
end
-
-
# Given a secret and a valid salt (see BCrypt::Engine.generate_salt) calculates
-
# a bcrypt() password hash.
-
1
def self.hash_secret(secret, salt, cost = nil)
-
2
if valid_secret?(secret)
-
2
if valid_salt?(salt)
-
2
if cost.nil?
-
1
cost = autodetect_cost(salt)
-
end
-
-
2
if RUBY_PLATFORM == "java"
-
Java.bcrypt_jruby.BCrypt.hashpw(secret.to_s, salt.to_s)
-
else
-
2
__bc_crypt(secret.to_s, salt)
-
end
-
else
-
raise Errors::InvalidSalt.new("invalid salt")
-
end
-
else
-
raise Errors::InvalidSecret.new("invalid secret")
-
end
-
end
-
-
# Generates a random salt with a given computational cost.
-
1
def self.generate_salt(cost = DEFAULT_COST)
-
1
cost = cost.to_i
-
1
if cost > 0
-
1
if cost < MIN_COST
-
cost = MIN_COST
-
end
-
1
if RUBY_PLATFORM == "java"
-
Java.bcrypt_jruby.BCrypt.gensalt(cost)
-
else
-
1
prefix = "$2a$05$CCCCCCCCCCCCCCCCCCCCC.E5YPO9kmyuRGyh0XouQYb4YMJKvyOeW"
-
1
__bc_salt(prefix, cost, OpenSSL::Random.random_bytes(MAX_SALT_LENGTH))
-
end
-
else
-
raise Errors::InvalidCost.new("cost must be numeric and > 0")
-
end
-
end
-
-
# Returns true if +salt+ is a valid bcrypt() salt, false if not.
-
1
def self.valid_salt?(salt)
-
2
!!(salt =~ /^\$[0-9a-z]{2,}\$[0-9]{2,}\$[A-Za-z0-9\.\/]{22,}$/)
-
end
-
-
# Returns true if +secret+ is a valid bcrypt() secret, false if not.
-
1
def self.valid_secret?(secret)
-
2
secret.respond_to?(:to_s)
-
end
-
-
# Returns the cost factor which will result in computation times less than +upper_time_limit_in_ms+.
-
#
-
# Example:
-
#
-
# BCrypt.calibrate(200) #=> 10
-
# BCrypt.calibrate(1000) #=> 12
-
#
-
# # should take less than 200ms
-
# BCrypt::Password.create("woo", :cost => 10)
-
#
-
# # should take less than 1000ms
-
# BCrypt::Password.create("woo", :cost => 12)
-
1
def self.calibrate(upper_time_limit_in_ms)
-
40.times do |i|
-
start_time = Time.now
-
Password.create("testing testing", :cost => i+1)
-
end_time = Time.now - start_time
-
return i if end_time * 1_000 > upper_time_limit_in_ms
-
end
-
end
-
-
# Autodetects the cost from the salt string.
-
1
def self.autodetect_cost(salt)
-
1
salt[4..5].to_i
-
end
-
end
-
-
# A password management class which allows you to safely store users' passwords and compare them.
-
#
-
# Example usage:
-
#
-
# include BCrypt
-
#
-
# # hash a user's password
-
# @password = Password.create("my grand secret")
-
# @password #=> "$2a$10$GtKs1Kbsig8ULHZzO1h2TetZfhO4Fmlxphp8bVKnUlZCBYYClPohG"
-
#
-
# # store it safely
-
# @user.update_attribute(:password, @password)
-
#
-
# # read it back
-
# @user.reload!
-
# @db_password = Password.new(@user.password)
-
#
-
# # compare it after retrieval
-
# @db_password == "my grand secret" #=> true
-
# @db_password == "a paltry guess" #=> false
-
#
-
1
class Password < String
-
# The hash portion of the stored password hash.
-
1
attr_reader :checksum
-
# The salt of the store password hash (including version and cost).
-
1
attr_reader :salt
-
# The version of the bcrypt() algorithm used to create the hash.
-
1
attr_reader :version
-
# The cost factor used to create the hash.
-
1
attr_reader :cost
-
-
1
class << self
-
# Hashes a secret, returning a BCrypt::Password instance. Takes an optional <tt>:cost</tt> option, which is a
-
# logarithmic variable which determines how computational expensive the hash is to calculate (a <tt>:cost</tt> of
-
# 4 is twice as much work as a <tt>:cost</tt> of 3). The higher the <tt>:cost</tt> the harder it becomes for
-
# attackers to try to guess passwords (even if a copy of your database is stolen), but the slower it is to check
-
# users' passwords.
-
#
-
# Example:
-
#
-
# @password = BCrypt::Password.create("my secret", :cost => 13)
-
1
def create(secret, options = { :cost => BCrypt::Engine::DEFAULT_COST })
-
1
raise ArgumentError if options[:cost] > 31
-
1
Password.new(BCrypt::Engine.hash_secret(secret, BCrypt::Engine.generate_salt(options[:cost]), options[:cost]))
-
end
-
end
-
-
# Initializes a BCrypt::Password instance with the data from a stored hash.
-
1
def initialize(raw_hash)
-
3
if valid_hash?(raw_hash)
-
3
self.replace(raw_hash)
-
3
@version, @cost, @salt, @checksum = split_hash(self)
-
else
-
raise Errors::InvalidHash.new("invalid hash")
-
end
-
end
-
-
# Compares a potential secret against the hash. Returns true if the secret is the original secret, false otherwise.
-
1
def ==(secret)
-
1
super(BCrypt::Engine.hash_secret(secret, @salt))
-
end
-
1
alias_method :is_password?, :==
-
-
1
private
-
# Returns true if +h+ is a valid hash.
-
1
def valid_hash?(h)
-
3
h =~ /^\$[0-9a-z]{2}\$[0-9]{2}\$[A-Za-z0-9\.\/]{53}$/
-
end
-
-
# call-seq:
-
# split_hash(raw_hash) -> version, cost, salt, hash
-
#
-
# Splits +h+ into version, cost, salt, and hash and returns them in that order.
-
1
def split_hash(h)
-
3
_, v, c, mash = h.split('$')
-
3
return v, c.to_i, h[0, 29].to_str, mash[-31, 31].to_str
-
end
-
end
-
end
-
#!/usr/bin/env ruby
-
-
#--
-
# Copyright 2004 by Jim Weirich (jim@weirichhouse.org).
-
# All rights reserved.
-
-
# Permission is granted for use, copying, modification, distribution,
-
# and distribution of modified versions of this work as long as the
-
# above copyright notice is included.
-
#++
-
-
1
require 'builder/xmlmarkup'
-
1
require 'builder/xmlevents'
-
#!/usr/bin/env ruby
-
#--
-
# Copyright 2004, 2006 by Jim Weirich (jim@weirichhouse.org).
-
# All rights reserved.
-
-
# Permission is granted for use, copying, modification, distribution,
-
# and distribution of modified versions of this work as long as the
-
# above copyright notice is included.
-
#++
-
-
######################################################################
-
# BlankSlate has been promoted to a top level name and is now
-
# available as a standalone gem. We make the name available in the
-
# Builder namespace for compatibility.
-
#
-
1
module Builder
-
1
if Object::const_defined?(:BasicObject)
-
1
BlankSlate = ::BasicObject
-
else
-
require 'blankslate'
-
BlankSlate = ::BlankSlate
-
end
-
end
-
#!/usr/bin/env ruby
-
-
# The XChar library is provided courtesy of Sam Ruby (See
-
# http://intertwingly.net/stories/2005/09/28/xchar.rb)
-
-
# --------------------------------------------------------------------
-
-
# If the Builder::XChar module is not currently defined, fail on any
-
# name clashes in standard library classes.
-
-
1
module Builder
-
1
def self.check_for_name_collision(klass, method_name, defined_constant=nil)
-
if klass.method_defined?(method_name.to_s)
-
fail RuntimeError,
-
"Name Collision: Method '#{method_name}' is already defined in #{klass}"
-
end
-
end
-
end
-
-
1
if ! defined?(Builder::XChar) and ! String.method_defined?(:encode)
-
Builder.check_for_name_collision(String, "to_xs")
-
Builder.check_for_name_collision(Fixnum, "xchr")
-
end
-
-
######################################################################
-
1
module Builder
-
-
####################################################################
-
# XML Character converter, from Sam Ruby:
-
# (see http://intertwingly.net/stories/2005/09/28/xchar.rb).
-
#
-
1
module XChar # :nodoc:
-
-
# See
-
# http://intertwingly.net/stories/2004/04/14/i18n.html#CleaningWindows
-
# for details.
-
1
CP1252 = { # :nodoc:
-
128 => 8364, # euro sign
-
130 => 8218, # single low-9 quotation mark
-
131 => 402, # latin small letter f with hook
-
132 => 8222, # double low-9 quotation mark
-
133 => 8230, # horizontal ellipsis
-
134 => 8224, # dagger
-
135 => 8225, # double dagger
-
136 => 710, # modifier letter circumflex accent
-
137 => 8240, # per mille sign
-
138 => 352, # latin capital letter s with caron
-
139 => 8249, # single left-pointing angle quotation mark
-
140 => 338, # latin capital ligature oe
-
142 => 381, # latin capital letter z with caron
-
145 => 8216, # left single quotation mark
-
146 => 8217, # right single quotation mark
-
147 => 8220, # left double quotation mark
-
148 => 8221, # right double quotation mark
-
149 => 8226, # bullet
-
150 => 8211, # en dash
-
151 => 8212, # em dash
-
152 => 732, # small tilde
-
153 => 8482, # trade mark sign
-
154 => 353, # latin small letter s with caron
-
155 => 8250, # single right-pointing angle quotation mark
-
156 => 339, # latin small ligature oe
-
158 => 382, # latin small letter z with caron
-
159 => 376, # latin capital letter y with diaeresis
-
}
-
-
# See http://www.w3.org/TR/REC-xml/#dt-chardata for details.
-
1
PREDEFINED = {
-
38 => '&', # ampersand
-
60 => '<', # left angle bracket
-
62 => '>', # right angle bracket
-
}
-
-
# See http://www.w3.org/TR/REC-xml/#charsets for details.
-
1
VALID = [
-
0x9, 0xA, 0xD,
-
(0x20..0xD7FF),
-
(0xE000..0xFFFD),
-
(0x10000..0x10FFFF)
-
]
-
-
# http://www.fileformat.info/info/unicode/char/fffd/index.htm
-
1
REPLACEMENT_CHAR =
-
if String.method_defined?(:encode)
-
1
"\uFFFD"
-
elsif $KCODE == 'UTF8'
-
"\xEF\xBF\xBD"
-
else
-
'*'
-
end
-
end
-
-
end
-
-
-
1
if String.method_defined?(:encode)
-
1
module Builder
-
1
module XChar # :nodoc:
-
1
CP1252_DIFFERENCES, UNICODE_EQUIVALENT = Builder::XChar::CP1252.each.
-
inject([[],[]]) {|(domain,range),(key,value)|
-
27
[domain << key,range << value]
-
2
}.map {|seq| seq.pack('U*').force_encoding('utf-8')}
-
-
1
XML_PREDEFINED = Regexp.new('[' +
-
Builder::XChar::PREDEFINED.keys.pack('U*').force_encoding('utf-8') +
-
']')
-
-
1
INVALID_XML_CHAR = Regexp.new('[^'+
-
Builder::XChar::VALID.map { |item|
-
6
case item
-
when Fixnum
-
3
[item].pack('U').force_encoding('utf-8')
-
when Range
-
3
[item.first, '-'.ord, item.last].pack('UUU').force_encoding('utf-8')
-
end
-
}.join +
-
']')
-
-
1
ENCODING_BINARY = Encoding.find('BINARY')
-
1
ENCODING_UTF8 = Encoding.find('UTF-8')
-
1
ENCODING_ISO1 = Encoding.find('ISO-8859-1')
-
-
# convert a string to valid UTF-8, compensating for a number of
-
# common errors.
-
1
def XChar.unicode(string)
-
3427
if string.encoding == ENCODING_BINARY
-
if string.ascii_only?
-
string
-
else
-
string = string.clone.force_encoding(ENCODING_UTF8)
-
if string.valid_encoding?
-
string
-
else
-
string.encode(ENCODING_UTF8, ENCODING_ISO1)
-
end
-
end
-
-
3427
elsif string.encoding == ENCODING_UTF8
-
if string.valid_encoding?
-
string
-
else
-
string.encode(ENCODING_UTF8, ENCODING_ISO1)
-
end
-
-
else
-
3427
string.encode(ENCODING_UTF8)
-
end
-
end
-
-
# encode a string per XML rules
-
1
def XChar.encode(string)
-
3427
unicode(string).
-
tr(CP1252_DIFFERENCES, UNICODE_EQUIVALENT).
-
gsub(INVALID_XML_CHAR, REPLACEMENT_CHAR).
-
4
gsub(XML_PREDEFINED) {|c| PREDEFINED[c.ord]}
-
end
-
end
-
end
-
-
else
-
-
######################################################################
-
# Enhance the Fixnum class with a XML escaped character conversion.
-
#
-
class Fixnum
-
XChar = Builder::XChar if ! defined?(XChar)
-
-
# XML escaped version of chr. When <tt>escape</tt> is set to false
-
# the CP1252 fix is still applied but utf-8 characters are not
-
# converted to character entities.
-
def xchr(escape=true)
-
n = XChar::CP1252[self] || self
-
case n when *XChar::VALID
-
XChar::PREDEFINED[n] or
-
(n<128 ? n.chr : (escape ? "&##{n};" : [n].pack('U*')))
-
else
-
Builder::XChar::REPLACEMENT_CHAR
-
end
-
end
-
end
-
-
-
######################################################################
-
# Enhance the String class with a XML escaped character version of
-
# to_s.
-
#
-
class String
-
# XML escaped version of to_s. When <tt>escape</tt> is set to false
-
# the CP1252 fix is still applied but utf-8 characters are not
-
# converted to character entities.
-
def to_xs(escape=true)
-
unpack('U*').map {|n| n.xchr(escape)}.join # ASCII, UTF-8
-
rescue
-
unpack('C*').map {|n| n.xchr}.join # ISO-8859-1, WIN-1252
-
end
-
end
-
end
-
#!/usr/bin/env ruby
-
-
1
require 'builder/blankslate'
-
-
1
module Builder
-
-
# Generic error for builder
-
1
class IllegalBlockError < RuntimeError; end
-
-
# XmlBase is a base class for building XML builders. See
-
# Builder::XmlMarkup and Builder::XmlEvents for examples.
-
1
class XmlBase < BlankSlate
-
-
1
class << self
-
1
attr_accessor :cache_method_calls
-
end
-
-
# Create an XML markup builder.
-
#
-
# out:: Object receiving the markup. +out+ must respond to
-
# <tt><<</tt>.
-
# indent:: Number of spaces used for indentation (0 implies no
-
# indentation and no line breaks).
-
# initial:: Level of initial indentation.
-
# encoding:: When <tt>encoding</tt> and $KCODE are set to 'utf-8'
-
# characters aren't converted to character entities in
-
# the output stream.
-
1
def initialize(indent=0, initial=0, encoding='utf-8')
-
64
@indent = indent
-
64
@level = initial
-
64
@encoding = encoding.downcase
-
end
-
-
# Create a tag named +sym+. Other than the first argument which
-
# is the tag name, the arguments are the same as the tags
-
# implemented via <tt>method_missing</tt>.
-
1
def tag!(sym, *args, &block)
-
1167
text = nil
-
1167
attrs = nil
-
1167
sym = "#{sym}:#{args.shift}" if args.first.kind_of?(::Symbol)
-
1167
sym = sym.to_sym unless sym.class == ::Symbol
-
1167
args.each do |arg|
-
2067
case arg
-
when ::Hash
-
1050
attrs ||= {}
-
1050
attrs.merge!(arg)
-
when nil
-
# do nothing
-
else
-
764
text ||= ''
-
764
text << arg.to_s
-
end
-
end
-
1167
if block
-
146
unless text.nil?
-
::Kernel::raise ::ArgumentError,
-
"XmlMarkup cannot mix a text argument with a block"
-
end
-
146
_indent
-
146
_start_tag(sym, attrs)
-
146
_newline
-
146
begin
-
146
_nested_structures(block)
-
ensure
-
146
_indent
-
146
_end_tag(sym)
-
146
_newline
-
end
-
elsif text.nil?
-
257
_indent
-
257
_start_tag(sym, attrs, true)
-
257
_newline
-
else
-
764
_indent
-
764
_start_tag(sym, attrs)
-
764
text! text
-
764
_end_tag(sym)
-
764
_newline
-
end
-
1167
@target
-
end
-
-
# Create XML markup based on the name of the method. This method
-
# is never invoked directly, but is called for each markup method
-
# in the markup block that isn't cached.
-
1
def method_missing(sym, *args, &block)
-
1
cache_method_call(sym) if ::Builder::XmlBase.cache_method_calls
-
1
tag!(sym, *args, &block)
-
end
-
-
# Append text to the output target. Escape any markup. May be
-
# used within the markup brackets as:
-
#
-
# builder.p { |b| b.br; b.text! "HI" } #=> <p><br/>HI</p>
-
1
def text!(text)
-
2335
_text(_escape(text))
-
end
-
-
# Append text to the output target without escaping any markup.
-
# May be used within the markup brackets as:
-
#
-
# builder.p { |x| x << "<br/>HI" } #=> <p><br/>HI</p>
-
#
-
# This is useful when using non-builder enabled software that
-
# generates strings. Just insert the string directly into the
-
# builder without changing the inserted markup.
-
#
-
# It is also useful for stacking builder objects. Builders only
-
# use <tt><<</tt> to append to the target, so by supporting this
-
# method/operation builders can use other builders as their
-
# targets.
-
1
def <<(text)
-
_text(text)
-
end
-
-
# For some reason, nil? is sent to the XmlMarkup object. If nil?
-
# is not defined and method_missing is invoked, some strange kind
-
# of recursion happens. Since nil? won't ever be an XML tag, it
-
# is pretty safe to define it here. (Note: this is an example of
-
# cargo cult programming,
-
# cf. http://fishbowl.pastiche.org/2004/10/13/cargo_cult_programming).
-
1
def nil?
-
false
-
end
-
-
1
private
-
-
1
require 'builder/xchar'
-
1
if ::String.method_defined?(:encode)
-
1
def _escape(text)
-
3427
result = XChar.encode(text)
-
3427
begin
-
3427
encoding = ::Encoding::find(@encoding)
-
3427
raise Exception if encoding.dummy?
-
3427
result.encode(encoding)
-
rescue
-
# if the encoding can't be supported, use numeric character references
-
result.
-
gsub(/[^\u0000-\u007F]/) {|c| "&##{c.ord};"}.
-
force_encoding('ascii')
-
end
-
end
-
else
-
def _escape(text)
-
if (text.method(:to_xs).arity == 0)
-
text.to_xs
-
else
-
text.to_xs((@encoding != 'utf-8' or $KCODE != 'UTF8'))
-
end
-
end
-
end
-
-
1
def _escape_attribute(text)
-
1092
_escape(text).gsub("\n", " ").gsub("\r", " ").
-
gsub(%r{"}, '"') # " WART
-
end
-
-
1
def _newline
-
1360
return if @indent == 0
-
850
text! "\n"
-
end
-
-
1
def _indent
-
1360
return if @indent == 0 || @level == 0
-
721
text!(" " * (@level * @indent))
-
end
-
-
1
def _nested_structures(block)
-
146
@level += 1
-
146
block.call(self)
-
ensure
-
146
@level -= 1
-
end
-
-
# If XmlBase.cache_method_calls = true, we dynamicly create the method
-
# missed as an instance method on the XMLBase object. Because XML
-
# documents are usually very repetative in nature, the next node will
-
# be handled by the new method instead of method_missing. As
-
# method_missing is very slow, this speeds up document generation
-
# significantly.
-
1
def cache_method_call(sym)
-
2
class << self; self; end.class_eval do
-
1
define_method(sym) do |*args, &block|
-
tag!(sym, *args, &block)
-
end
-
end
-
end
-
end
-
-
1
XmlBase.cache_method_calls = true
-
-
end
-
#!/usr/bin/env ruby
-
-
#--
-
# Copyright 2004 by Jim Weirich (jim@weirichhouse.org).
-
# All rights reserved.
-
-
# Permission is granted for use, copying, modification, distribution,
-
# and distribution of modified versions of this work as long as the
-
# above copyright notice is included.
-
#++
-
-
1
require 'builder/xmlmarkup'
-
-
1
module Builder
-
-
# Create a series of SAX-like XML events (e.g. start_tag, end_tag)
-
# from the markup code. XmlEvent objects are used in a way similar
-
# to XmlMarkup objects, except that a series of events are generated
-
# and passed to a handler rather than generating character-based
-
# markup.
-
#
-
# Usage:
-
# xe = Builder::XmlEvents.new(hander)
-
# xe.title("HI") # Sends start_tag/end_tag/text messages to the handler.
-
#
-
# Indentation may also be selected by providing value for the
-
# indentation size and initial indentation level.
-
#
-
# xe = Builder::XmlEvents.new(handler, indent_size, initial_indent_level)
-
#
-
# == XML Event Handler
-
#
-
# The handler object must expect the following events.
-
#
-
# [<tt>start_tag(tag, attrs)</tt>]
-
# Announces that a new tag has been found. +tag+ is the name of
-
# the tag and +attrs+ is a hash of attributes for the tag.
-
#
-
# [<tt>end_tag(tag)</tt>]
-
# Announces that an end tag for +tag+ has been found.
-
#
-
# [<tt>text(text)</tt>]
-
# Announces that a string of characters (+text+) has been found.
-
# A series of characters may be broken up into more than one
-
# +text+ call, so the client cannot assume that a single
-
# callback contains all the text data.
-
#
-
1
class XmlEvents < XmlMarkup
-
1
def text!(text)
-
@target.text(text)
-
end
-
-
1
def _start_tag(sym, attrs, end_too=false)
-
@target.start_tag(sym, attrs)
-
_end_tag(sym) if end_too
-
end
-
-
1
def _end_tag(sym)
-
@target.end_tag(sym)
-
end
-
end
-
-
end
-
#!/usr/bin/env ruby
-
#--
-
# Copyright 2004, 2005 by Jim Weirich (jim@weirichhouse.org).
-
# All rights reserved.
-
-
# Permission is granted for use, copying, modification, distribution,
-
# and distribution of modified versions of this work as long as the
-
# above copyright notice is included.
-
#++
-
-
# Provide a flexible and easy to use Builder for creating XML markup.
-
# See XmlBuilder for usage details.
-
-
1
require 'builder/xmlbase'
-
-
1
module Builder
-
-
# Create XML markup easily. All (well, almost all) methods sent to
-
# an XmlMarkup object will be translated to the equivalent XML
-
# markup. Any method with a block will be treated as an XML markup
-
# tag with nested markup in the block.
-
#
-
# Examples will demonstrate this easier than words. In the
-
# following, +xm+ is an +XmlMarkup+ object.
-
#
-
# xm.em("emphasized") # => <em>emphasized</em>
-
# xm.em { xm.b("emp & bold") } # => <em><b>emph & bold</b></em>
-
# xm.a("A Link", "href"=>"http://onestepback.org")
-
# # => <a href="http://onestepback.org">A Link</a>
-
# xm.div { xm.br } # => <div><br/></div>
-
# xm.target("name"=>"compile", "option"=>"fast")
-
# # => <target option="fast" name="compile"\>
-
# # NOTE: order of attributes is not specified.
-
#
-
# xm.instruct! # <?xml version="1.0" encoding="UTF-8"?>
-
# xm.html { # <html>
-
# xm.head { # <head>
-
# xm.title("History") # <title>History</title>
-
# } # </head>
-
# xm.body { # <body>
-
# xm.comment! "HI" # <!-- HI -->
-
# xm.h1("Header") # <h1>Header</h1>
-
# xm.p("paragraph") # <p>paragraph</p>
-
# } # </body>
-
# } # </html>
-
#
-
# == Notes:
-
#
-
# * The order that attributes are inserted in markup tags is
-
# undefined.
-
#
-
# * Sometimes you wish to insert text without enclosing tags. Use
-
# the <tt>text!</tt> method to accomplish this.
-
#
-
# Example:
-
#
-
# xm.div { # <div>
-
# xm.text! "line"; xm.br # line<br/>
-
# xm.text! "another line"; xmbr # another line<br/>
-
# } # </div>
-
#
-
# * The special XML characters <, >, and & are converted to <,
-
# > and & automatically. Use the <tt><<</tt> operation to
-
# insert text without modification.
-
#
-
# * Sometimes tags use special characters not allowed in ruby
-
# identifiers. Use the <tt>tag!</tt> method to handle these
-
# cases.
-
#
-
# Example:
-
#
-
# xml.tag!("SOAP:Envelope") { ... }
-
#
-
# will produce ...
-
#
-
# <SOAP:Envelope> ... </SOAP:Envelope>"
-
#
-
# <tt>tag!</tt> will also take text and attribute arguments (after
-
# the tag name) like normal markup methods. (But see the next
-
# bullet item for a better way to handle XML namespaces).
-
#
-
# * Direct support for XML namespaces is now available. If the
-
# first argument to a tag call is a symbol, it will be joined to
-
# the tag to produce a namespace:tag combination. It is easier to
-
# show this than describe it.
-
#
-
# xml.SOAP :Envelope do ... end
-
#
-
# Just put a space before the colon in a namespace to produce the
-
# right form for builder (e.g. "<tt>SOAP:Envelope</tt>" =>
-
# "<tt>xml.SOAP :Envelope</tt>")
-
#
-
# * XmlMarkup builds the markup in any object (called a _target_)
-
# that accepts the <tt><<</tt> method. If no target is given,
-
# then XmlMarkup defaults to a string target.
-
#
-
# Examples:
-
#
-
# xm = Builder::XmlMarkup.new
-
# result = xm.title("yada")
-
# # result is a string containing the markup.
-
#
-
# buffer = ""
-
# xm = Builder::XmlMarkup.new(buffer)
-
# # The markup is appended to buffer (using <<)
-
#
-
# xm = Builder::XmlMarkup.new(STDOUT)
-
# # The markup is written to STDOUT (using <<)
-
#
-
# xm = Builder::XmlMarkup.new
-
# x2 = Builder::XmlMarkup.new(:target=>xm)
-
# # Markup written to +x2+ will be send to +xm+.
-
#
-
# * Indentation is enabled by providing the number of spaces to
-
# indent for each level as a second argument to XmlBuilder.new.
-
# Initial indentation may be specified using a third parameter.
-
#
-
# Example:
-
#
-
# xm = Builder.new(:indent=>2)
-
# # xm will produce nicely formatted and indented XML.
-
#
-
# xm = Builder.new(:indent=>2, :margin=>4)
-
# # xm will produce nicely formatted and indented XML with 2
-
# # spaces per indent and an over all indentation level of 4.
-
#
-
# builder = Builder::XmlMarkup.new(:target=>$stdout, :indent=>2)
-
# builder.name { |b| b.first("Jim"); b.last("Weirich) }
-
# # prints:
-
# # <name>
-
# # <first>Jim</first>
-
# # <last>Weirich</last>
-
# # </name>
-
#
-
# * The instance_eval implementation which forces self to refer to
-
# the message receiver as self is now obsolete. We now use normal
-
# block calls to execute the markup block. This means that all
-
# markup methods must now be explicitly send to the xml builder.
-
# For instance, instead of
-
#
-
# xml.div { strong("text") }
-
#
-
# you need to write:
-
#
-
# xml.div { xml.strong("text") }
-
#
-
# Although more verbose, the subtle change in semantics within the
-
# block was found to be prone to error. To make this change a
-
# little less cumbersome, the markup block now gets the markup
-
# object sent as an argument, allowing you to use a shorter alias
-
# within the block.
-
#
-
# For example:
-
#
-
# xml_builder = Builder::XmlMarkup.new
-
# xml_builder.div { |xml|
-
# xml.stong("text")
-
# }
-
#
-
1
class XmlMarkup < XmlBase
-
-
# Create an XML markup builder. Parameters are specified by an
-
# option hash.
-
#
-
# :target=><em>target_object</em>::
-
# Object receiving the markup. +target_object+ must respond to
-
# the <tt><<(<em>a_string</em>)</tt> operator and return
-
# itself. The default target is a plain string target.
-
#
-
# :indent=><em>indentation</em>::
-
# Number of spaces used for indentation. The default is no
-
# indentation and no line breaks.
-
#
-
# :margin=><em>initial_indentation_level</em>::
-
# Amount of initial indentation (specified in levels, not
-
# spaces).
-
#
-
# :escape_attrs=><em>OBSOLETE</em>::
-
# The :escape_attrs option is no longer supported by builder
-
# (and will be quietly ignored). String attribute values are
-
# now automatically escaped. If you need unescaped attribute
-
# values (perhaps you are using entities in the attribute
-
# values), then give the value as a Symbol. This allows much
-
# finer control over escaping attribute values.
-
#
-
1
def initialize(options={})
-
64
indent = options[:indent] || 0
-
64
margin = options[:margin] || 0
-
64
super(indent, margin)
-
64
@target = options[:target] || ""
-
end
-
-
# Return the target of the builder.
-
1
def target!
-
@target
-
end
-
-
1
def comment!(comment_text)
-
_ensure_no_block ::Kernel::block_given?
-
_special("<!-- ", " -->", comment_text, nil)
-
end
-
-
# Insert an XML declaration into the XML markup.
-
#
-
# For example:
-
#
-
# xml.declare! :ELEMENT, :blah, "yada"
-
# # => <!ELEMENT blah "yada">
-
1
def declare!(inst, *args, &block)
-
_indent
-
@target << "<!#{inst}"
-
args.each do |arg|
-
case arg
-
when ::String
-
@target << %{ "#{arg}"} # " WART
-
when ::Symbol
-
@target << " #{arg}"
-
end
-
end
-
if ::Kernel::block_given?
-
@target << " ["
-
_newline
-
_nested_structures(block)
-
@target << "]"
-
end
-
@target << ">"
-
_newline
-
end
-
-
# Insert a processing instruction into the XML markup. E.g.
-
#
-
# For example:
-
#
-
# xml.instruct!
-
# #=> <?xml version="1.0" encoding="UTF-8"?>
-
# xml.instruct! :aaa, :bbb=>"ccc"
-
# #=> <?aaa bbb="ccc"?>
-
#
-
# Note: If the encoding is setup to "UTF-8" and the value of
-
# $KCODE is "UTF8", then builder will emit UTF-8 encoded strings
-
# rather than the entity encoding normally used.
-
1
def instruct!(directive_tag=:xml, attrs={})
-
47
_ensure_no_block ::Kernel::block_given?
-
47
if directive_tag == :xml
-
47
a = { :version=>"1.0", :encoding=>"UTF-8" }
-
47
attrs = a.merge attrs
-
47
@encoding = attrs[:encoding].downcase
-
end
-
_special(
-
47
"<?#{directive_tag}",
-
"?>",
-
nil,
-
attrs,
-
[:version, :encoding, :standalone])
-
end
-
-
# Insert a CDATA section into the XML markup.
-
#
-
# For example:
-
#
-
# xml.cdata!("text to be included in cdata")
-
# #=> <![CDATA[text to be included in cdata]]>
-
#
-
1
def cdata!(text)
-
_ensure_no_block ::Kernel::block_given?
-
_special("<![CDATA[", "]]>", text.gsub(']]>', ']]]]><![CDATA[>'), nil)
-
end
-
-
1
private
-
-
# NOTE: All private methods of a builder object are prefixed when
-
# a "_" character to avoid possible conflict with XML tag names.
-
-
# Insert text directly in to the builder's target.
-
1
def _text(text)
-
2335
@target << text
-
end
-
-
# Insert special instruction.
-
1
def _special(open, close, data=nil, attrs=nil, order=[])
-
47
_indent
-
47
@target << open
-
47
@target << data if data
-
47
_insert_attributes(attrs, order) if attrs
-
47
@target << close
-
47
_newline
-
end
-
-
# Start an XML tag. If <tt>end_too</tt> is true, then the start
-
# tag is also the end tag (e.g. <br/>
-
1
def _start_tag(sym, attrs, end_too=false)
-
1167
@target << "<#{sym}"
-
1167
_insert_attributes(attrs)
-
1167
@target << "/" if end_too
-
1167
@target << ">"
-
end
-
-
# Insert an ending tag.
-
1
def _end_tag(sym)
-
910
@target << "</#{sym}>"
-
end
-
-
# Insert the attributes (given in the hash).
-
1
def _insert_attributes(attrs, order=[])
-
1214
return if attrs.nil?
-
1097
order.each do |k|
-
141
v = attrs[k]
-
141
@target << %{ #{k}="#{_attr_value(v)}"} if v # " WART
-
end
-
1097
attrs.each do |k, v|
-
1092
@target << %{ #{k}="#{_attr_value(v)}"} unless order.member?(k) # " WART
-
end
-
end
-
-
1
def _attr_value(value)
-
1092
case value
-
when ::Symbol
-
value.to_s
-
else
-
1092
_escape_attribute(value.to_s)
-
end
-
end
-
-
1
def _ensure_no_block(got_block)
-
47
if got_block
-
::Kernel::raise IllegalBlockError.new(
-
"Blocks are not allowed on XML instructions"
-
)
-
end
-
end
-
-
end
-
-
end
-
##
-
## $Release: 2.7.0 $
-
## copyright(c) 2006-2011 kuwata-lab.com all rights reserved.
-
##
-
-
##
-
## an implementation of eRuby
-
##
-
## ex.
-
## input = <<'END'
-
## <ul>
-
## <% for item in @list %>
-
## <li><%= item %>
-
## <%== item %></li>
-
## <% end %>
-
## </ul>
-
## END
-
## list = ['<aaa>', 'b&b', '"ccc"']
-
## eruby = Erubis::Eruby.new(input)
-
## puts "--- code ---"
-
## puts eruby.src
-
## puts "--- result ---"
-
## context = Erubis::Context.new() # or new(:list=>list)
-
## context[:list] = list
-
## puts eruby.evaluate(context)
-
##
-
## result:
-
## --- source ---
-
## _buf = ''; _buf << '<ul>
-
## '; for item in @list
-
## _buf << ' <li>'; _buf << ( item ).to_s; _buf << '
-
## '; _buf << ' '; _buf << Erubis::XmlHelper.escape_xml( item ); _buf << '</li>
-
## '; end
-
## _buf << '</ul>
-
## ';
-
## _buf.to_s
-
## --- result ---
-
## <ul>
-
## <li><aaa>
-
## <aaa></li>
-
## <li>b&b
-
## b&b</li>
-
## <li>"ccc"
-
## "ccc"</li>
-
## </ul>
-
##
-
-
-
2
module Erubis
-
2
VERSION = ('$Release: 2.7.0 $' =~ /([.\d]+)/) && $1
-
end
-
-
2
require 'erubis/engine'
-
#require 'erubis/generator'
-
#require 'erubis/converter'
-
#require 'erubis/evaluator'
-
#require 'erubis/error'
-
#require 'erubis/context'
-
#requier 'erubis/util'
-
2
require 'erubis/helper'
-
2
require 'erubis/enhancer'
-
#require 'erubis/tiny'
-
2
require 'erubis/engine/eruby'
-
#require 'erubis/engine/enhanced' # enhanced eruby engines
-
#require 'erubis/engine/optimized' # generates optimized ruby code
-
#require 'erubis/engine/ephp'
-
#require 'erubis/engine/ec'
-
#require 'erubis/engine/ejava'
-
#require 'erubis/engine/escheme'
-
#require 'erubis/engine/eperl'
-
#require 'erubis/engine/ejavascript'
-
-
2
require 'erubis/local-setting'
-
##
-
## $Release: 2.7.0 $
-
## copyright(c) 2006-2011 kuwata-lab.com all rights reserved.
-
##
-
-
-
2
module Erubis
-
-
-
##
-
## context object for Engine#evaluate
-
##
-
## ex.
-
## template = <<'END'
-
## Hello <%= @user %>!
-
## <% for item in @list %>
-
## - <%= item %>
-
## <% end %>
-
## END
-
##
-
## context = Erubis::Context.new(:user=>'World', :list=>['a','b','c'])
-
## # or
-
## # context = Erubis::Context.new
-
## # context[:user] = 'World'
-
## # context[:list] = ['a', 'b', 'c']
-
##
-
## eruby = Erubis::Eruby.new(template)
-
## print eruby.evaluate(context)
-
##
-
2
class Context
-
2
include Enumerable
-
-
2
def initialize(hash=nil)
-
hash.each do |name, value|
-
self[name] = value
-
end if hash
-
end
-
-
2
def [](key)
-
return instance_variable_get("@#{key}")
-
end
-
-
2
def []=(key, value)
-
return instance_variable_set("@#{key}", value)
-
end
-
-
2
def keys
-
return instance_variables.collect { |name| name[1..-1] }
-
end
-
-
2
def each
-
instance_variables.each do |name|
-
key = name[1..-1]
-
value = instance_variable_get(name)
-
yield(key, value)
-
end
-
end
-
-
2
def to_hash
-
hash = {}
-
self.keys.each { |key| hash[key] = self[key] }
-
return hash
-
end
-
-
2
def update(context_or_hash)
-
arg = context_or_hash
-
if arg.is_a?(Hash)
-
arg.each do |key, val|
-
self[key] = val
-
end
-
else
-
arg.instance_variables.each do |varname|
-
key = varname[1..-1]
-
val = arg.instance_variable_get(varname)
-
self[key] = val
-
end
-
end
-
end
-
-
end
-
-
-
end
-
##
-
## $Release: 2.7.0 $
-
## copyright(c) 2006-2011 kuwata-lab.com all rights reserved.
-
##
-
-
2
require 'erubis/util'
-
-
2
module Erubis
-
-
-
##
-
## convert
-
##
-
2
module Converter
-
-
2
attr_accessor :preamble, :postamble, :escape
-
-
2
def self.supported_properties # :nodoc:
-
return [
-
[:preamble, nil, "preamble (no preamble when false)"],
-
[:postamble, nil, "postamble (no postamble when false)"],
-
[:escape, nil, "escape expression or not in default"],
-
]
-
end
-
-
2
def init_converter(properties={})
-
1
@preamble = properties[:preamble]
-
1
@postamble = properties[:postamble]
-
1
@escape = properties[:escape]
-
end
-
-
## convert input string into target language
-
2
def convert(input)
-
1
codebuf = "" # or []
-
1
@preamble.nil? ? add_preamble(codebuf) : (@preamble && (codebuf << @preamble))
-
1
convert_input(codebuf, input)
-
1
@postamble.nil? ? add_postamble(codebuf) : (@postamble && (codebuf << @postamble))
-
1
@_proc = nil # clear cached proc object
-
1
return codebuf # or codebuf.join()
-
end
-
-
2
protected
-
-
##
-
## detect spaces at beginning of line
-
##
-
2
def detect_spaces_at_bol(text, is_bol)
-
lspace = nil
-
if text.empty?
-
lspace = "" if is_bol
-
elsif text[-1] == ?\n
-
lspace = ""
-
else
-
rindex = text.rindex(?\n)
-
if rindex
-
s = text[rindex+1..-1]
-
if s =~ /\A[ \t]*\z/
-
lspace = s
-
#text = text[0..rindex]
-
text[rindex+1..-1] = ''
-
end
-
else
-
if is_bol && text =~ /\A[ \t]*\z/
-
#lspace = text
-
#text = nil
-
lspace = text.dup
-
text[0..-1] = ''
-
end
-
end
-
end
-
return lspace
-
end
-
-
##
-
## (abstract) convert input to code
-
##
-
2
def convert_input(codebuf, input)
-
not_implemented
-
end
-
-
end
-
-
-
2
module Basic
-
end
-
-
-
##
-
## basic converter which supports '<% ... %>' notation.
-
##
-
2
module Basic::Converter
-
2
include Erubis::Converter
-
-
2
def self.supported_properties # :nodoc:
-
return [
-
[:pattern, '<% %>', "embed pattern"],
-
[:trim, true, "trim spaces around <% ... %>"],
-
]
-
end
-
-
2
attr_accessor :pattern, :trim
-
-
2
def init_converter(properties={})
-
1
super(properties)
-
1
@pattern = properties[:pattern]
-
1
@trim = properties[:trim] != false
-
end
-
-
2
protected
-
-
## return regexp of pattern to parse eRuby script
-
2
def pattern_regexp(pattern)
-
2
@prefix, @postfix = pattern.split() # '<% %>' => '<%', '%>'
-
#return /(.*?)(^[ \t]*)?#{@prefix}(=+|\#)?(.*?)-?#{@postfix}([ \t]*\r?\n)?/m
-
#return /(^[ \t]*)?#{@prefix}(=+|\#)?(.*?)-?#{@postfix}([ \t]*\r?\n)?/m
-
2
return /#{@prefix}(=+|-|\#|%)?(.*?)([-=])?#{@postfix}([ \t]*\r?\n)?/m
-
end
-
2
module_function :pattern_regexp
-
-
#DEFAULT_REGEXP = /(.*?)(^[ \t]*)?<%(=+|\#)?(.*?)-?%>([ \t]*\r?\n)?/m
-
#DEFAULT_REGEXP = /(^[ \t]*)?<%(=+|\#)?(.*?)-?%>([ \t]*\r?\n)?/m
-
#DEFAULT_REGEXP = /<%(=+|\#)?(.*?)-?%>([ \t]*\r?\n)?/m
-
2
DEFAULT_REGEXP = pattern_regexp('<% %>')
-
-
2
public
-
-
2
def convert_input(src, input)
-
1
pat = @pattern
-
1
regexp = pat.nil? || pat == '<% %>' ? DEFAULT_REGEXP : pattern_regexp(pat)
-
1
pos = 0
-
1
is_bol = true # is beginning of line
-
1
input.scan(regexp) do |indicator, code, tailch, rspace|
-
15
match = Regexp.last_match()
-
15
len = match.begin(0) - pos
-
15
text = input[pos, len]
-
15
pos = match.end(0)
-
15
ch = indicator ? indicator[0] : nil
-
15
lspace = ch == ?= ? nil : detect_spaces_at_bol(text, is_bol)
-
15
is_bol = rspace ? true : false
-
15
add_text(src, text) if text && !text.empty?
-
## * when '<%= %>', do nothing
-
## * when '<% %>' or '<%# %>', delete spaces iff only spaces are around '<% %>'
-
15
if ch == ?= # <%= %>
-
15
rspace = nil if tailch && !tailch.empty?
-
15
add_text(src, lspace) if lspace
-
15
add_expr(src, code, indicator)
-
15
add_text(src, rspace) if rspace
-
elsif ch == ?\# # <%# %>
-
n = code.count("\n") + (rspace ? 1 : 0)
-
if @trim && lspace && rspace
-
add_stmt(src, "\n" * n)
-
else
-
add_text(src, lspace) if lspace
-
add_stmt(src, "\n" * n)
-
add_text(src, rspace) if rspace
-
end
-
elsif ch == ?% # <%% %>
-
s = "#{lspace}#{@prefix||='<%'}#{code}#{tailch}#{@postfix||='%>'}#{rspace}"
-
add_text(src, s)
-
else # <% %>
-
if @trim && lspace && rspace
-
add_stmt(src, "#{lspace}#{code}#{rspace}")
-
else
-
add_text(src, lspace) if lspace
-
add_stmt(src, code)
-
add_text(src, rspace) if rspace
-
end
-
end
-
end
-
#rest = $' || input # ruby1.8
-
1
rest = pos == 0 ? input : input[pos..-1] # ruby1.9
-
1
add_text(src, rest)
-
end
-
-
## add expression code to src
-
2
def add_expr(src, code, indicator)
-
15
case indicator
-
when '='
-
15
@escape ? add_expr_escaped(src, code) : add_expr_literal(src, code)
-
when '=='
-
@escape ? add_expr_literal(src, code) : add_expr_escaped(src, code)
-
when '==='
-
add_expr_debug(src, code)
-
end
-
end
-
-
end
-
-
-
2
module PI
-
end
-
-
##
-
## Processing Instructions (PI) converter for XML.
-
## this class converts '<?rb ... ?>' and '${...}' notation.
-
##
-
2
module PI::Converter
-
2
include Erubis::Converter
-
-
2
def self.desc # :nodoc:
-
"use processing instructions (PI) instead of '<% %>'"
-
end
-
-
2
def self.supported_properties # :nodoc:
-
return [
-
[:trim, true, "trim spaces around <% ... %>"],
-
[:pi, 'rb', "PI (Processing Instrunctions) name"],
-
[:embchar, '@', "char for embedded expression pattern('@{...}@')"],
-
[:pattern, '<% %>', "embed pattern"],
-
]
-
end
-
-
2
attr_accessor :pi, :prefix
-
-
2
def init_converter(properties={})
-
super(properties)
-
@trim = properties.fetch(:trim, true)
-
@pi = properties[:pi] if properties[:pi]
-
@embchar = properties[:embchar] || '@'
-
@pattern = properties[:pattern]
-
@pattern = '<% %>' if @pattern.nil? #|| @pattern == true
-
end
-
-
2
def convert(input)
-
code = super(input)
-
return @header || @footer ? "#{@header}#{code}#{@footer}" : code
-
end
-
-
2
protected
-
-
2
def convert_input(codebuf, input)
-
unless @regexp
-
@pi ||= 'e'
-
ch = Regexp.escape(@embchar)
-
if @pattern
-
left, right = @pattern.split(' ')
-
@regexp = /<\?#{@pi}(?:-(\w+))?(\s.*?)\?>([ \t]*\r?\n)?|#{ch}(!*)?\{(.*?)\}#{ch}|#{left}(=+)(.*?)#{right}/m
-
else
-
@regexp = /<\?#{@pi}(?:-(\w+))?(\s.*?)\?>([ \t]*\r?\n)?|#{ch}(!*)?\{(.*?)\}#{ch}/m
-
end
-
end
-
#
-
is_bol = true
-
pos = 0
-
input.scan(@regexp) do |pi_arg, stmt, rspace,
-
indicator1, expr1, indicator2, expr2|
-
match = Regexp.last_match
-
len = match.begin(0) - pos
-
text = input[pos, len]
-
pos = match.end(0)
-
lspace = stmt ? detect_spaces_at_bol(text, is_bol) : nil
-
is_bol = stmt && rspace ? true : false
-
add_text(codebuf, text) # unless text.empty?
-
#
-
if stmt
-
if @trim && lspace && rspace
-
add_pi_stmt(codebuf, "#{lspace}#{stmt}#{rspace}", pi_arg)
-
else
-
add_text(codebuf, lspace) if lspace
-
add_pi_stmt(codebuf, stmt, pi_arg)
-
add_text(codebuf, rspace) if rspace
-
end
-
else
-
add_pi_expr(codebuf, expr1 || expr2, indicator1 || indicator2)
-
end
-
end
-
#rest = $' || input # ruby1.8
-
rest = pos == 0 ? input : input[pos..-1] # ruby1.9
-
add_text(codebuf, rest)
-
end
-
-
#--
-
#def convert_input(codebuf, input)
-
# parse_stmts(codebuf, input)
-
# #parse_stmts2(codebuf, input)
-
#end
-
#
-
#def parse_stmts(codebuf, input)
-
# #regexp = pattern_regexp(@pattern)
-
# @pi ||= 'e'
-
# @stmt_pattern ||= /<\?#{@pi}(?:-(\w+))?(\s.*?)\?>([ \t]*\r?\n)?/m
-
# is_bol = true
-
# pos = 0
-
# input.scan(@stmt_pattern) do |pi_arg, code, rspace|
-
# match = Regexp.last_match
-
# len = match.begin(0) - pos
-
# text = input[pos, len]
-
# pos = match.end(0)
-
# lspace = detect_spaces_at_bol(text, is_bol)
-
# is_bol = rspace ? true : false
-
# parse_exprs(codebuf, text) # unless text.empty?
-
# if @trim && lspace && rspace
-
# add_pi_stmt(codebuf, "#{lspace}#{code}#{rspace}", pi_arg)
-
# else
-
# add_text(codebuf, lspace)
-
# add_pi_stmt(codebuf, code, pi_arg)
-
# add_text(codebuf, rspace)
-
# end
-
# end
-
# rest = $' || input
-
# parse_exprs(codebuf, rest)
-
#end
-
#
-
#def parse_exprs(codebuf, input)
-
# unless @expr_pattern
-
# ch = Regexp.escape(@embchar)
-
# if @pattern
-
# left, right = @pattern.split(' ')
-
# @expr_pattern = /#{ch}(!*)?\{(.*?)\}#{ch}|#{left}(=+)(.*?)#{right}/
-
# else
-
# @expr_pattern = /#{ch}(!*)?\{(.*?)\}#{ch}/
-
# end
-
# end
-
# pos = 0
-
# input.scan(@expr_pattern) do |indicator1, code1, indicator2, code2|
-
# indicator = indicator1 || indicator2
-
# code = code1 || code2
-
# match = Regexp.last_match
-
# len = match.begin(0) - pos
-
# text = input[pos, len]
-
# pos = match.end(0)
-
# add_text(codebuf, text) # unless text.empty?
-
# add_pi_expr(codebuf, code, indicator)
-
# end
-
# rest = $' || input
-
# add_text(codebuf, rest)
-
#end
-
#++
-
-
2
def add_pi_stmt(codebuf, code, pi_arg) # :nodoc:
-
case pi_arg
-
when nil ; add_stmt(codebuf, code)
-
when 'header' ; @header = code
-
when 'footer' ; @footer = code
-
when 'comment'; add_stmt(codebuf, "\n" * code.count("\n"))
-
when 'value' ; add_expr_literal(codebuf, code)
-
else ; add_stmt(codebuf, code)
-
end
-
end
-
-
2
def add_pi_expr(codebuf, code, indicator) # :nodoc:
-
case indicator
-
when nil, '', '==' # @{...}@ or <%== ... %>
-
@escape == false ? add_expr_literal(codebuf, code) : add_expr_escaped(codebuf, code)
-
when '!', '=' # @!{...}@ or <%= ... %>
-
@escape == false ? add_expr_escaped(codebuf, code) : add_expr_literal(codebuf, code)
-
when '!!', '===' # @!!{...}@ or <%=== ... %>
-
add_expr_debug(codebuf, code)
-
else
-
# ignore
-
end
-
end
-
-
end
-
-
-
end
-
##
-
## $Release: 2.7.0 $
-
## copyright(c) 2006-2011 kuwata-lab.com all rights reserved.
-
##
-
-
-
2
require 'erubis/generator'
-
2
require 'erubis/converter'
-
2
require 'erubis/evaluator'
-
2
require 'erubis/context'
-
-
-
2
module Erubis
-
-
-
##
-
## (abstract) abstract engine class.
-
## subclass must include evaluator and converter module.
-
##
-
2
class Engine
-
#include Evaluator
-
#include Converter
-
#include Generator
-
-
2
def initialize(input=nil, properties={})
-
#@input = input
-
1
init_generator(properties)
-
1
init_converter(properties)
-
1
init_evaluator(properties)
-
1
@src = convert(input) if input
-
end
-
-
-
##
-
## convert input string and set it to @src
-
##
-
2
def convert!(input)
-
@src = convert(input)
-
end
-
-
-
##
-
## load file, write cache file, and return engine object.
-
## this method create code cache file automatically.
-
## cachefile name can be specified with properties[:cachename],
-
## or filname + 'cache' is used as default.
-
##
-
2
def self.load_file(filename, properties={})
-
cachename = properties[:cachename] || (filename + '.cache')
-
properties[:filename] = filename
-
timestamp = File.mtime(filename)
-
if test(?f, cachename) && timestamp == File.mtime(cachename)
-
engine = self.new(nil, properties)
-
engine.src = File.read(cachename)
-
else
-
input = File.open(filename, 'rb') {|f| f.read }
-
engine = self.new(input, properties)
-
tmpname = cachename + rand().to_s[1,8]
-
File.open(tmpname, 'wb') {|f| f.write(engine.src) }
-
File.rename(tmpname, cachename)
-
File.utime(timestamp, timestamp, cachename)
-
end
-
engine.src.untaint # ok?
-
return engine
-
end
-
-
-
##
-
## helper method to convert and evaluate input text with context object.
-
## context may be Binding, Hash, or Object.
-
##
-
2
def process(input, context=nil, filename=nil)
-
code = convert(input)
-
filename ||= '(erubis)'
-
if context.is_a?(Binding)
-
return eval(code, context, filename)
-
else
-
context = Context.new(context) if context.is_a?(Hash)
-
return context.instance_eval(code, filename)
-
end
-
end
-
-
-
##
-
## helper method evaluate Proc object with contect object.
-
## context may be Binding, Hash, or Object.
-
##
-
2
def process_proc(proc_obj, context=nil, filename=nil)
-
if context.is_a?(Binding)
-
filename ||= '(erubis)'
-
return eval(proc_obj, context, filename)
-
else
-
context = Context.new(context) if context.is_a?(Hash)
-
return context.instance_eval(&proc_obj)
-
end
-
end
-
-
-
end # end of class Engine
-
-
-
##
-
## (abstract) base engine class for Eruby, Eperl, Ejava, and so on.
-
## subclass must include generator.
-
##
-
2
class Basic::Engine < Engine
-
2
include Evaluator
-
2
include Basic::Converter
-
2
include Generator
-
end
-
-
-
2
class PI::Engine < Engine
-
2
include Evaluator
-
2
include PI::Converter
-
2
include Generator
-
end
-
-
-
end
-
##
-
## $Release: 2.7.0 $
-
## copyright(c) 2006-2011 kuwata-lab.com all rights reserved.
-
##
-
-
-
2
module Erubis
-
-
-
##
-
## switch '<%= ... %>' to escaped and '<%== ... %>' to unescaped
-
##
-
## ex.
-
## class XmlEruby < Eruby
-
## include EscapeEnhancer
-
## end
-
##
-
## this is language-indenedent.
-
##
-
2
module EscapeEnhancer
-
-
2
def self.desc # :nodoc:
-
"switch '<%= %>' to escaped and '<%== %>' to unescaped"
-
end
-
-
#--
-
#def self.included(klass)
-
# klass.class_eval <<-END
-
# alias _add_expr_literal add_expr_literal
-
# alias _add_expr_escaped add_expr_escaped
-
# alias add_expr_literal _add_expr_escaped
-
# alias add_expr_escaped _add_expr_literal
-
# END
-
#end
-
#++
-
-
2
def add_expr(src, code, indicator)
-
case indicator
-
when '='
-
@escape ? add_expr_literal(src, code) : add_expr_escaped(src, code)
-
when '=='
-
@escape ? add_expr_escaped(src, code) : add_expr_literal(src, code)
-
when '==='
-
add_expr_debug(src, code)
-
end
-
end
-
-
end
-
-
-
#--
-
## (obsolete)
-
#module FastEnhancer
-
#end
-
#++
-
-
-
##
-
## use $stdout instead of string
-
##
-
## this is only for Eruby.
-
##
-
2
module StdoutEnhancer
-
-
2
def self.desc # :nodoc:
-
"use $stdout instead of array buffer or string buffer"
-
end
-
-
2
def add_preamble(src)
-
src << "#{@bufvar} = $stdout;"
-
end
-
-
2
def add_postamble(src)
-
src << "\n''\n"
-
end
-
-
end
-
-
-
##
-
## use print statement instead of '_buf << ...'
-
##
-
## this is only for Eruby.
-
##
-
2
module PrintOutEnhancer
-
-
2
def self.desc # :nodoc:
-
"use print statement instead of '_buf << ...'"
-
end
-
-
2
def add_preamble(src)
-
end
-
-
2
def add_text(src, text)
-
src << " print '#{escape_text(text)}';" unless text.empty?
-
end
-
-
2
def add_expr_literal(src, code)
-
src << " print((#{code}).to_s);"
-
end
-
-
2
def add_expr_escaped(src, code)
-
src << " print #{escaped_expr(code)};"
-
end
-
-
2
def add_postamble(src)
-
src << "\n" unless src[-1] == ?\n
-
end
-
-
end
-
-
-
##
-
## enable print function
-
##
-
## Notice: use Eruby#evaluate() and don't use Eruby#result()
-
## to be enable print function.
-
##
-
## this is only for Eruby.
-
##
-
2
module PrintEnabledEnhancer
-
-
2
def self.desc # :nodoc:
-
"enable to use print function in '<% %>'"
-
end
-
-
2
def add_preamble(src)
-
src << "@_buf = "
-
super
-
end
-
-
2
def print(*args)
-
args.each do |arg|
-
@_buf << arg.to_s
-
end
-
end
-
-
2
def evaluate(context=nil)
-
_src = @src
-
if context.is_a?(Hash)
-
context.each do |key, val| instance_variable_set("@#{key}", val) end
-
elsif context
-
context.instance_variables.each do |name|
-
instance_variable_set(name, context.instance_variable_get(name))
-
end
-
end
-
return instance_eval(_src, (@filename || '(erubis)'))
-
end
-
-
end
-
-
-
##
-
## return array instead of string
-
##
-
## this is only for Eruby.
-
##
-
2
module ArrayEnhancer
-
-
2
def self.desc # :nodoc:
-
"return array instead of string"
-
end
-
-
2
def add_preamble(src)
-
src << "#{@bufvar} = [];"
-
end
-
-
2
def add_postamble(src)
-
src << "\n" unless src[-1] == ?\n
-
src << "#{@bufvar}\n"
-
end
-
-
end
-
-
-
##
-
## use an Array object as buffer (included in Eruby by default)
-
##
-
## this is only for Eruby.
-
##
-
2
module ArrayBufferEnhancer
-
-
2
def self.desc # :nodoc:
-
"use an Array object for buffering (included in Eruby class)"
-
end
-
-
2
def add_preamble(src)
-
src << "_buf = [];"
-
end
-
-
2
def add_postamble(src)
-
src << "\n" unless src[-1] == ?\n
-
src << "_buf.join\n"
-
end
-
-
end
-
-
-
##
-
## use String class for buffering
-
##
-
## this is only for Eruby.
-
##
-
2
module StringBufferEnhancer
-
-
2
def self.desc # :nodoc:
-
"use a String object for buffering"
-
end
-
-
2
def add_preamble(src)
-
1
src << "#{@bufvar} = '';"
-
end
-
-
2
def add_postamble(src)
-
1
src << "\n" unless src[-1] == ?\n
-
1
src << "#{@bufvar}.to_s\n"
-
end
-
-
end
-
-
-
##
-
## use StringIO class for buffering
-
##
-
## this is only for Eruby.
-
##
-
2
module StringIOEnhancer # :nodoc:
-
-
2
def self.desc # :nodoc:
-
"use a StringIO object for buffering"
-
end
-
-
2
def add_preamble(src)
-
src << "#{@bufvar} = StringIO.new;"
-
end
-
-
2
def add_postamble(src)
-
src << "\n" unless src[-1] == ?\n
-
src << "#{@bufvar}.string\n"
-
end
-
-
end
-
-
-
##
-
## set buffer variable name to '_erbout' as well as '_buf'
-
##
-
## this is only for Eruby.
-
##
-
2
module ErboutEnhancer
-
-
2
def self.desc # :nodoc:
-
"set '_erbout = _buf = \"\";' to be compatible with ERB."
-
end
-
-
2
def add_preamble(src)
-
src << "_erbout = #{@bufvar} = '';"
-
end
-
-
2
def add_postamble(src)
-
src << "\n" unless src[-1] == ?\n
-
src << "#{@bufvar}.to_s\n"
-
end
-
-
end
-
-
-
##
-
## remove text and leave code, especially useful when debugging.
-
##
-
## ex.
-
## $ erubis -s -E NoText file.eruby | more
-
##
-
## this is language independent.
-
##
-
2
module NoTextEnhancer
-
-
2
def self.desc # :nodoc:
-
"remove text and leave code (useful when debugging)"
-
end
-
-
2
def add_text(src, text)
-
src << ("\n" * text.count("\n"))
-
if text[-1] != ?\n
-
text =~ /^(.*?)\z/
-
src << (' ' * $1.length)
-
end
-
end
-
-
end
-
-
-
##
-
## remove code and leave text, especially useful when validating HTML tags.
-
##
-
## ex.
-
## $ erubis -s -E NoCode file.eruby | tidy -errors
-
##
-
## this is language independent.
-
##
-
2
module NoCodeEnhancer
-
-
2
def self.desc # :nodoc:
-
"remove code and leave text (useful when validating HTML)"
-
end
-
-
2
def add_preamble(src)
-
end
-
-
2
def add_postamble(src)
-
end
-
-
2
def add_text(src, text)
-
src << text
-
end
-
-
2
def add_expr(src, code, indicator)
-
src << "\n" * code.count("\n")
-
end
-
-
2
def add_stmt(src, code)
-
src << "\n" * code.count("\n")
-
end
-
-
end
-
-
-
##
-
## get convert faster, but spaces around '<%...%>' are not trimmed.
-
##
-
## this is language-independent.
-
##
-
2
module SimplifyEnhancer
-
-
2
def self.desc # :nodoc:
-
"get convert faster but leave spaces around '<% %>'"
-
end
-
-
#DEFAULT_REGEXP = /(^[ \t]*)?<%(=+|\#)?(.*?)-?%>([ \t]*\r?\n)?/m
-
2
SIMPLE_REGEXP = /<%(=+|\#)?(.*?)-?%>/m
-
-
2
def convert(input)
-
src = ""
-
add_preamble(src)
-
#regexp = pattern_regexp(@pattern)
-
pos = 0
-
input.scan(SIMPLE_REGEXP) do |indicator, code|
-
match = Regexp.last_match
-
index = match.begin(0)
-
text = input[pos, index - pos]
-
pos = match.end(0)
-
add_text(src, text)
-
if !indicator # <% %>
-
add_stmt(src, code)
-
elsif indicator[0] == ?\# # <%# %>
-
n = code.count("\n")
-
add_stmt(src, "\n" * n)
-
else # <%= %>
-
add_expr(src, code, indicator)
-
end
-
end
-
#rest = $' || input # ruby1.8
-
rest = pos == 0 ? input : input[pos..-1] # ruby1.9
-
add_text(src, rest)
-
add_postamble(src)
-
return src
-
end
-
-
end
-
-
-
##
-
## enable to use other embedded expression pattern (default is '\[= =\]').
-
##
-
## notice! this is an experimental. spec may change in the future.
-
##
-
## ex.
-
## input = <<END
-
## <% for item in list %>
-
## <%= item %> : <%== item %>
-
## [= item =] : [== item =]
-
## <% end %>
-
## END
-
##
-
## class BiPatternEruby
-
## include BiPatternEnhancer
-
## end
-
## eruby = BiPatternEruby.new(input, :bipattern=>'\[= =\]')
-
## list = ['<a>', 'b&b', '"c"']
-
## print eruby.result(binding())
-
##
-
## ## output
-
## <a> : <a>
-
## <a> : <a>
-
## b&b : b&b
-
## b&b : b&b
-
## "c" : "c"
-
## "c" : "c"
-
##
-
## this is language independent.
-
##
-
2
module BiPatternEnhancer
-
-
2
def self.desc # :nodoc:
-
"another embedded expression pattern (default '\[= =\]')."
-
end
-
-
2
def initialize(input, properties={})
-
self.bipattern = properties[:bipattern] # or '\$\{ \}'
-
super
-
end
-
-
## when pat is nil then '\[= =\]' is used
-
2
def bipattern=(pat) # :nodoc:
-
@bipattern = pat || '\[= =\]'
-
pre, post = @bipattern.split()
-
@bipattern_regexp = /(.*?)#{pre}(=*)(.*?)#{post}/m
-
end
-
-
2
def add_text(src, text)
-
return unless text
-
m = nil
-
text.scan(@bipattern_regexp) do |txt, indicator, code|
-
m = Regexp.last_match
-
super(src, txt)
-
add_expr(src, code, '=' + indicator)
-
end
-
#rest = $' || text # ruby1.8
-
rest = m ? text[m.end(0)..-1] : text # ruby1.9
-
super(src, rest)
-
end
-
-
end
-
-
-
##
-
## regards lines starting with '^[ \t]*%' as program code
-
##
-
## in addition you can specify prefix character (default '%')
-
##
-
## this is language-independent.
-
##
-
2
module PrefixedLineEnhancer
-
-
2
def self.desc # :nodoc:
-
"regard lines matched to '^[ \t]*%' as program code"
-
end
-
-
2
def init_generator(properties={})
-
super
-
@prefixchar = properties[:prefixchar]
-
end
-
-
2
def add_text(src, text)
-
unless @prefixrexp
-
@prefixchar ||= '%'
-
@prefixrexp = Regexp.compile("^([ \\t]*)\\#{@prefixchar}(.*?\\r?\\n)")
-
end
-
pos = 0
-
text2 = ''
-
text.scan(@prefixrexp) do
-
space = $1
-
line = $2
-
space, line = '', $1 unless $2
-
match = Regexp.last_match
-
len = match.begin(0) - pos
-
str = text[pos, len]
-
pos = match.end(0)
-
if text2.empty?
-
text2 = str
-
else
-
text2 << str
-
end
-
if line[0, 1] == @prefixchar
-
text2 << space << line
-
else
-
super(src, text2)
-
text2 = ''
-
add_stmt(src, space + line)
-
end
-
end
-
#rest = pos == 0 ? text : $' # ruby1.8
-
rest = pos == 0 ? text : text[pos..-1] # ruby1.9
-
unless text2.empty?
-
text2 << rest if rest
-
rest = text2
-
end
-
super(src, rest)
-
end
-
-
end
-
-
-
##
-
## regards lines starting with '%' as program code
-
##
-
## this is for compatibility to eruby and ERB.
-
##
-
## this is language-independent.
-
##
-
2
module PercentLineEnhancer
-
2
include PrefixedLineEnhancer
-
-
2
def self.desc # :nodoc:
-
"regard lines starting with '%' as program code"
-
end
-
-
#--
-
#def init_generator(properties={})
-
# super
-
# @prefixchar = '%'
-
# @prefixrexp = /^\%(.*?\r?\n)/
-
#end
-
#++
-
-
2
def add_text(src, text)
-
unless @prefixrexp
-
@prefixchar = '%'
-
@prefixrexp = /^\%(.*?\r?\n)/
-
end
-
super(src, text)
-
end
-
-
end
-
-
-
##
-
## [experimental] allow header and footer in eRuby script
-
##
-
## ex.
-
## ====================
-
## ## without header and footer
-
## $ cat ex1.eruby
-
## <% def list_items(list) %>
-
## <% for item in list %>
-
## <li><%= item %></li>
-
## <% end %>
-
## <% end %>
-
##
-
## $ erubis -s ex1.eruby
-
## _buf = []; def list_items(list)
-
## ; for item in list
-
## ; _buf << '<li>'; _buf << ( item ).to_s; _buf << '</li>
-
## '; end
-
## ; end
-
## ;
-
## _buf.join
-
##
-
## ## with header and footer
-
## $ cat ex2.eruby
-
## <!--#header:
-
## def list_items(list)
-
## #-->
-
## <% for item in list %>
-
## <li><%= item %></li>
-
## <% end %>
-
## <!--#footer:
-
## end
-
## #-->
-
##
-
## $ erubis -s -c HeaderFooterEruby ex4.eruby
-
##
-
## def list_items(list)
-
## _buf = []; _buf << '
-
## '; for item in list
-
## ; _buf << '<li>'; _buf << ( item ).to_s; _buf << '</li>
-
## '; end
-
## ; _buf << '
-
## ';
-
## _buf.join
-
## end
-
##
-
## ====================
-
##
-
## this is language-independent.
-
##
-
2
module HeaderFooterEnhancer
-
-
2
def self.desc # :nodoc:
-
"allow header/footer in document (ex. '<!--#header: #-->')"
-
end
-
-
2
HEADER_FOOTER_PATTERN = /(.*?)(^[ \t]*)?<!--\#(\w+):(.*?)\#-->([ \t]*\r?\n)?/m
-
-
2
def add_text(src, text)
-
m = nil
-
text.scan(HEADER_FOOTER_PATTERN) do |txt, lspace, word, content, rspace|
-
m = Regexp.last_match
-
flag_trim = @trim && lspace && rspace
-
super(src, txt)
-
content = "#{lspace}#{content}#{rspace}" if flag_trim
-
super(src, lspace) if !flag_trim && lspace
-
instance_variable_set("@#{word}", content)
-
super(src, rspace) if !flag_trim && rspace
-
end
-
#rest = $' || text # ruby1.8
-
rest = m ? text[m.end(0)..-1] : text # ruby1.9
-
super(src, rest)
-
end
-
-
2
attr_accessor :header, :footer
-
-
2
def convert(input)
-
source = super
-
return @src = "#{@header}#{source}#{@footer}"
-
end
-
-
end
-
-
-
##
-
## delete indentation of HTML.
-
##
-
## this is language-independent.
-
##
-
2
module DeleteIndentEnhancer
-
-
2
def self.desc # :nodoc:
-
"delete indentation of HTML."
-
end
-
-
2
def convert_input(src, input)
-
input = input.gsub(/^[ \t]+</, '<')
-
super(src, input)
-
end
-
-
end
-
-
-
##
-
## convert "<h1><%=title%></h1>" into "_buf << %Q`<h1>#{title}</h1>`"
-
##
-
## this is only for Eruby.
-
##
-
2
module InterpolationEnhancer
-
-
2
def self.desc # :nodoc:
-
"convert '<p><%=text%></p>' into '_buf << %Q`<p>\#{text}</p>`'"
-
end
-
-
2
def convert_input(src, input)
-
pat = @pattern
-
regexp = pat.nil? || pat == '<% %>' ? Basic::Converter::DEFAULT_REGEXP : pattern_regexp(pat)
-
pos = 0
-
is_bol = true # is beginning of line
-
str = ''
-
input.scan(regexp) do |indicator, code, tailch, rspace|
-
match = Regexp.last_match()
-
len = match.begin(0) - pos
-
text = input[pos, len]
-
pos = match.end(0)
-
ch = indicator ? indicator[0] : nil
-
lspace = ch == ?= ? nil : detect_spaces_at_bol(text, is_bol)
-
is_bol = rspace ? true : false
-
_add_text_to_str(str, text)
-
## * when '<%= %>', do nothing
-
## * when '<% %>' or '<%# %>', delete spaces iff only spaces are around '<% %>'
-
if ch == ?= # <%= %>
-
rspace = nil if tailch && !tailch.empty?
-
str << lspace if lspace
-
add_expr(str, code, indicator)
-
str << rspace if rspace
-
elsif ch == ?\# # <%# %>
-
n = code.count("\n") + (rspace ? 1 : 0)
-
if @trim && lspace && rspace
-
add_text(src, str)
-
str = ''
-
add_stmt(src, "\n" * n)
-
else
-
str << lspace if lspace
-
add_text(src, str)
-
str = ''
-
add_stmt(src, "\n" * n)
-
str << rspace if rspace
-
end
-
else # <% %>
-
if @trim && lspace && rspace
-
add_text(src, str)
-
str = ''
-
add_stmt(src, "#{lspace}#{code}#{rspace}")
-
else
-
str << lspace if lspace
-
add_text(src, str)
-
str = ''
-
add_stmt(src, code)
-
str << rspace if rspace
-
end
-
end
-
end
-
#rest = $' || input # ruby1.8
-
rest = pos == 0 ? input : input[pos..-1] # ruby1.9
-
_add_text_to_str(str, rest)
-
add_text(src, str)
-
end
-
-
2
def add_text(src, text)
-
return if !text || text.empty?
-
#src << " _buf << %Q`" << text << "`;"
-
if text[-1] == ?\n
-
text[-1] = "\\n"
-
src << " #{@bufvar} << %Q`#{text}`\n"
-
else
-
src << " #{@bufvar} << %Q`#{text}`;"
-
end
-
end
-
-
2
def _add_text_to_str(str, text)
-
return if !text || text.empty?
-
str << text.gsub(/[`\#\\]/, '\\\\\&')
-
end
-
-
2
def add_expr_escaped(str, code)
-
str << "\#{#{escaped_expr(code)}}"
-
end
-
-
2
def add_expr_literal(str, code)
-
str << "\#{#{code}}"
-
end
-
-
end
-
-
-
end
-
##
-
## $Release: 2.7.0 $
-
## copyright(c) 2006-2011 kuwata-lab.com all rights reserved.
-
##
-
-
2
module Erubis
-
-
-
##
-
## base error class
-
##
-
2
class ErubisError < StandardError
-
end
-
-
-
##
-
## raised when method or function is not supported
-
##
-
2
class NotSupportedError < ErubisError
-
end
-
-
-
end
-
##
-
## $Release: 2.7.0 $
-
## copyright(c) 2006-2011 kuwata-lab.com all rights reserved.
-
##
-
-
2
require 'erubis/error'
-
2
require 'erubis/context'
-
-
-
2
module Erubis
-
-
2
EMPTY_BINDING = binding()
-
-
-
##
-
## evaluate code
-
##
-
2
module Evaluator
-
-
2
def self.supported_properties # :nodoc:
-
return []
-
end
-
-
2
attr_accessor :src, :filename
-
-
2
def init_evaluator(properties)
-
1
@filename = properties[:filename]
-
end
-
-
2
def result(*args)
-
raise NotSupportedError.new("evaluation of code except Ruby is not supported.")
-
end
-
-
2
def evaluate(*args)
-
raise NotSupportedError.new("evaluation of code except Ruby is not supported.")
-
end
-
-
end
-
-
-
##
-
## evaluator for Ruby
-
##
-
2
module RubyEvaluator
-
2
include Evaluator
-
-
2
def self.supported_properties # :nodoc:
-
list = Evaluator.supported_properties
-
return list
-
end
-
-
## eval(@src) with binding object
-
2
def result(_binding_or_hash=TOPLEVEL_BINDING)
-
1
_arg = _binding_or_hash
-
1
if _arg.is_a?(Hash)
-
_b = binding()
-
eval _arg.collect{|k,v| "#{k} = _arg[#{k.inspect}]; "}.join, _b
-
elsif _arg.is_a?(Binding)
-
1
_b = _arg
-
elsif _arg.nil?
-
_b = binding()
-
else
-
raise ArgumentError.new("#{self.class.name}#result(): argument should be Binding or Hash but passed #{_arg.class.name} object.")
-
end
-
1
return eval(@src, _b, (@filename || '(erubis'))
-
end
-
-
## invoke context.instance_eval(@src)
-
2
def evaluate(_context=Context.new)
-
_context = Context.new(_context) if _context.is_a?(Hash)
-
#return _context.instance_eval(@src, @filename || '(erubis)')
-
#@_proc ||= eval("proc { #{@src} }", Erubis::EMPTY_BINDING, @filename || '(erubis)')
-
@_proc ||= eval("proc { #{@src} }", binding(), @filename || '(erubis)')
-
return _context.instance_eval(&@_proc)
-
end
-
-
## if object is an Class or Module then define instance method to it,
-
## else define singleton method to it.
-
2
def def_method(object, method_name, filename=nil)
-
m = object.is_a?(Module) ? :module_eval : :instance_eval
-
object.__send__(m, "def #{method_name}; #{@src}; end", filename || @filename || '(erubis)')
-
end
-
-
-
end
-
-
-
end
-
##
-
## $Release: 2.7.0 $
-
## copyright(c) 2006-2011 kuwata-lab.com all rights reserved.
-
##
-
-
2
require 'erubis/util'
-
-
2
module Erubis
-
-
-
##
-
## code generator, called by Converter module
-
##
-
2
module Generator
-
-
2
def self.supported_properties() # :nodoc:
-
return [
-
[:escapefunc, nil, "escape function name"],
-
]
-
end
-
-
2
attr_accessor :escapefunc
-
-
2
def init_generator(properties={})
-
1
@escapefunc = properties[:escapefunc]
-
end
-
-
-
## (abstract) escape text string
-
##
-
## ex.
-
## def escape_text(text)
-
## return text.dump
-
## # or return "'" + text.gsub(/['\\]/, '\\\\\&') + "'"
-
## end
-
2
def escape_text(text)
-
not_implemented
-
end
-
-
## return escaped expression code (ex. 'h(...)' or 'htmlspecialchars(...)')
-
2
def escaped_expr(code)
-
code.strip!
-
return "#{@escapefunc}(#{code})"
-
end
-
-
## (abstract) add @preamble to src
-
2
def add_preamble(src)
-
not_implemented
-
end
-
-
## (abstract) add text string to src
-
2
def add_text(src, text)
-
not_implemented
-
end
-
-
## (abstract) add statement code to src
-
2
def add_stmt(src, code)
-
not_implemented
-
end
-
-
## (abstract) add expression literal code to src. this is called by add_expr().
-
2
def add_expr_literal(src, code)
-
not_implemented
-
end
-
-
## (abstract) add escaped expression code to src. this is called by add_expr().
-
2
def add_expr_escaped(src, code)
-
not_implemented
-
end
-
-
## (abstract) add expression code to src for debug. this is called by add_expr().
-
2
def add_expr_debug(src, code)
-
not_implemented
-
end
-
-
## (abstract) add @postamble to src
-
2
def add_postamble(src)
-
not_implemented
-
end
-
-
-
end
-
-
-
end
-
##
-
## $Release: 2.7.0 $
-
## copyright(c) 2006-2011 kuwata-lab.com all rights reserved.
-
##
-
-
-
2
module Erubis
-
-
##
-
## helper for xml
-
##
-
2
module XmlHelper
-
-
2
module_function
-
-
2
ESCAPE_TABLE = {
-
'&' => '&',
-
'<' => '<',
-
'>' => '>',
-
'"' => '"',
-
"'" => ''',
-
}
-
-
2
def escape_xml(value)
-
value.to_s.gsub(/[&<>"]/) { |s| ESCAPE_TABLE[s] } # or /[&<>"']/
-
#value.to_s.gsub(/[&<>"]/) { ESCAPE_TABLE[$&] }
-
end
-
-
2
def escape_xml2(value)
-
return value.to_s.gsub(/\&/,'&').gsub(/</,'<').gsub(/>/,'>').gsub(/"/,'"')
-
end
-
-
2
alias h escape_xml
-
2
alias html_escape escape_xml
-
-
2
def url_encode(str)
-
return str.gsub(/[^-_.a-zA-Z0-9]+/) { |s|
-
s.unpack('C*').collect { |i| "%%%02X" % i }.join
-
}
-
end
-
-
2
alias u url_encode
-
-
end
-
-
-
end
-
##
-
## $Release: 2.7.0 $
-
## copyright(c) 2006-2011 kuwata-lab.com all rights reserved.
-
##
-
-
##
-
## you can add site-local settings here.
-
## this files is required by erubis.rb
-
##
-
##
-
## $Release: 2.7.0 $
-
## copyright(c) 2006-2011 kuwata-lab.com all rights reserved.
-
##
-
-
2
module Kernel
-
-
##
-
## raise NotImplementedError
-
##
-
2
def not_implemented #:doc:
-
backtrace = caller()
-
method_name = (backtrace.shift =~ /`(\w+)'$/) && $1
-
mesg = "class #{self.class.name} must implement abstract method '#{method_name}()'."
-
#mesg = "#{self.class.name}##{method_name}() is not implemented."
-
err = NotImplementedError.new mesg
-
err.set_backtrace backtrace
-
raise err
-
end
-
2
private :not_implemented
-
-
end
-
1
require 'i18n/version'
-
1
require 'i18n/exceptions'
-
1
require 'i18n/interpolate/ruby'
-
-
1
module I18n
-
1
autoload :Backend, 'i18n/backend'
-
1
autoload :Config, 'i18n/config'
-
1
autoload :Gettext, 'i18n/gettext'
-
1
autoload :Locale, 'i18n/locale'
-
1
autoload :Tests, 'i18n/tests'
-
-
1
RESERVED_KEYS = [:scope, :default, :separator, :resolve, :object, :fallback, :format, :cascade, :throw, :raise, :rescue_format]
-
1
RESERVED_KEYS_PATTERN = /%\{(#{RESERVED_KEYS.join("|")})\}/
-
-
extend Module.new {
-
# Gets I18n configuration object.
-
1
def config
-
5992
Thread.current[:i18n_config] ||= I18n::Config.new
-
end
-
-
# Sets I18n configuration object.
-
1
def config=(value)
-
Thread.current[:i18n_config] = value
-
end
-
-
# Write methods which delegates to the configuration object
-
1
%w(locale backend default_locale available_locales default_separator
-
exception_handler load_path).each do |method|
-
7
module_eval <<-DELEGATORS, __FILE__, __LINE__ + 1
-
def #{method}
-
config.#{method}
-
end
-
-
def #{method}=(value)
-
config.#{method} = (value)
-
end
-
DELEGATORS
-
end
-
-
# Tells the backend to reload translations. Used in situations like the
-
# Rails development environment. Backends can implement whatever strategy
-
# is useful.
-
1
def reload!
-
config.backend.reload!
-
end
-
-
# Translates, pluralizes and interpolates a given key using a given locale,
-
# scope, and default, as well as interpolation values.
-
#
-
# *LOOKUP*
-
#
-
# Translation data is organized as a nested hash using the upper-level keys
-
# as namespaces. <em>E.g.</em>, ActionView ships with the translation:
-
# <tt>:date => {:formats => {:short => "%b %d"}}</tt>.
-
#
-
# Translations can be looked up at any level of this hash using the key argument
-
# and the scope option. <em>E.g.</em>, in this example <tt>I18n.t :date</tt>
-
# returns the whole translations hash <tt>{:formats => {:short => "%b %d"}}</tt>.
-
#
-
# Key can be either a single key or a dot-separated key (both Strings and Symbols
-
# work). <em>E.g.</em>, the short format can be looked up using both:
-
# I18n.t 'date.formats.short'
-
# I18n.t :'date.formats.short'
-
#
-
# Scope can be either a single key, a dot-separated key or an array of keys
-
# or dot-separated keys. Keys and scopes can be combined freely. So these
-
# examples will all look up the same short date format:
-
# I18n.t 'date.formats.short'
-
# I18n.t 'formats.short', :scope => 'date'
-
# I18n.t 'short', :scope => 'date.formats'
-
# I18n.t 'short', :scope => %w(date formats)
-
#
-
# *INTERPOLATION*
-
#
-
# Translations can contain interpolation variables which will be replaced by
-
# values passed to #translate as part of the options hash, with the keys matching
-
# the interpolation variable names.
-
#
-
# <em>E.g.</em>, with a translation <tt>:foo => "foo %{bar}"</tt> the option
-
# value for the key +bar+ will be interpolated into the translation:
-
# I18n.t :foo, :bar => 'baz' # => 'foo baz'
-
#
-
# *PLURALIZATION*
-
#
-
# Translation data can contain pluralized translations. Pluralized translations
-
# are arrays of singluar/plural versions of translations like <tt>['Foo', 'Foos']</tt>.
-
#
-
# Note that <tt>I18n::Backend::Simple</tt> only supports an algorithm for English
-
# pluralization rules. Other algorithms can be supported by custom backends.
-
#
-
# This returns the singular version of a pluralized translation:
-
# I18n.t :foo, :count => 1 # => 'Foo'
-
#
-
# These both return the plural version of a pluralized translation:
-
# I18n.t :foo, :count => 0 # => 'Foos'
-
# I18n.t :foo, :count => 2 # => 'Foos'
-
#
-
# The <tt>:count</tt> option can be used both for pluralization and interpolation.
-
# <em>E.g.</em>, with the translation
-
# <tt>:foo => ['%{count} foo', '%{count} foos']</tt>, count will
-
# be interpolated to the pluralized translation:
-
# I18n.t :foo, :count => 1 # => '1 foo'
-
#
-
# *DEFAULTS*
-
#
-
# This returns the translation for <tt>:foo</tt> or <tt>default</tt> if no translation was found:
-
# I18n.t :foo, :default => 'default'
-
#
-
# This returns the translation for <tt>:foo</tt> or the translation for <tt>:bar</tt> if no
-
# translation for <tt>:foo</tt> was found:
-
# I18n.t :foo, :default => :bar
-
#
-
# Returns the translation for <tt>:foo</tt> or the translation for <tt>:bar</tt>
-
# or <tt>default</tt> if no translations for <tt>:foo</tt> and <tt>:bar</tt> were found.
-
# I18n.t :foo, :default => [:bar, 'default']
-
#
-
# *BULK LOOKUP*
-
#
-
# This returns an array with the translations for <tt>:foo</tt> and <tt>:bar</tt>.
-
# I18n.t [:foo, :bar]
-
#
-
# Can be used with dot-separated nested keys:
-
# I18n.t [:'baz.foo', :'baz.bar']
-
#
-
# Which is the same as using a scope option:
-
# I18n.t [:foo, :bar], :scope => :baz
-
#
-
# *LAMBDAS*
-
#
-
# Both translations and defaults can be given as Ruby lambdas. Lambdas will be
-
# called and passed the key and options.
-
#
-
# E.g. assuming the key <tt>:salutation</tt> resolves to:
-
# lambda { |key, options| options[:gender] == 'm' ? "Mr. %{options[:name]}" : "Mrs. %{options[:name]}" }
-
#
-
# Then <tt>I18n.t(:salutation, :gender => 'w', :name => 'Smith') will result in "Mrs. Smith".
-
#
-
# It is recommended to use/implement lambdas in an "idempotent" way. E.g. when
-
# a cache layer is put in front of I18n.translate it will generate a cache key
-
# from the argument values passed to #translate. Therefor your lambdas should
-
# always return the same translations/values per unique combination of argument
-
# values.
-
1
def translate(*args)
-
2465
options = args.last.is_a?(Hash) ? args.pop : {}
-
2465
key = args.shift
-
2465
backend = config.backend
-
2465
locale = options.delete(:locale) || config.locale
-
2465
handling = options.delete(:throw) && :throw || options.delete(:raise) && :raise # TODO deprecate :raise
-
-
2465
raise I18n::ArgumentError if key.is_a?(String) && key.empty?
-
-
2465
result = catch(:exception) do
-
2465
if key.is_a?(Array)
-
key.map { |k| backend.translate(locale, k, options) }
-
else
-
2465
backend.translate(locale, key, options)
-
end
-
end
-
2465
result.is_a?(MissingTranslation) ? handle_exception(handling, result, locale, key, options) : result
-
end
-
1
alias :t :translate
-
-
# Wrapper for <tt>translate</tt> that adds <tt>:raise => true</tt>. With
-
# this option, if no translation is found, it will raise <tt>I18n::MissingTranslationData</tt>
-
1
def translate!(key, options={})
-
translate(key, options.merge(:raise => true))
-
end
-
1
alias :t! :translate!
-
-
# Transliterates UTF-8 characters to ASCII. By default this method will
-
# transliterate only Latin strings to an ASCII approximation:
-
#
-
# I18n.transliterate("Ærøskøbing")
-
# # => "AEroskobing"
-
#
-
# I18n.transliterate("日本語")
-
# # => "???"
-
#
-
# It's also possible to add support for per-locale transliterations. I18n
-
# expects transliteration rules to be stored at
-
# <tt>i18n.transliterate.rule</tt>.
-
#
-
# Transliteration rules can either be a Hash or a Proc. Procs must accept a
-
# single string argument. Hash rules inherit the default transliteration
-
# rules, while Procs do not.
-
#
-
# *Examples*
-
#
-
# Setting a Hash in <locale>.yml:
-
#
-
# i18n:
-
# transliterate:
-
# rule:
-
# ü: "ue"
-
# ö: "oe"
-
#
-
# Setting a Hash using Ruby:
-
#
-
# store_translations(:de, :i18n => {
-
# :transliterate => {
-
# :rule => {
-
# "ü" => "ue",
-
# "ö" => "oe"
-
# }
-
# }
-
# )
-
#
-
# Setting a Proc:
-
#
-
# translit = lambda {|string| MyTransliterator.transliterate(string) }
-
# store_translations(:xx, :i18n => {:transliterate => {:rule => translit})
-
#
-
# Transliterating strings:
-
#
-
# I18n.locale = :en
-
# I18n.transliterate("Jürgen") # => "Jurgen"
-
# I18n.locale = :de
-
# I18n.transliterate("Jürgen") # => "Juergen"
-
# I18n.transliterate("Jürgen", :locale => :en) # => "Jurgen"
-
# I18n.transliterate("Jürgen", :locale => :de) # => "Juergen"
-
1
def transliterate(*args)
-
options = args.pop if args.last.is_a?(Hash)
-
key = args.shift
-
locale = options && options.delete(:locale) || config.locale
-
handling = options && (options.delete(:throw) && :throw || options.delete(:raise) && :raise)
-
replacement = options && options.delete(:replacement)
-
config.backend.transliterate(locale, key, replacement)
-
rescue I18n::ArgumentError => exception
-
handle_exception(handling, exception, locale, key, options || {})
-
end
-
-
# Localizes certain objects, such as dates and numbers to local formatting.
-
1
def localize(object, options = {})
-
locale = options.delete(:locale) || config.locale
-
format = options.delete(:format) || :default
-
config.backend.localize(locale, object, format, options)
-
end
-
1
alias :l :localize
-
-
# Executes block with given I18n.locale set.
-
1
def with_locale(tmp_locale = nil)
-
if tmp_locale
-
current_locale = self.locale
-
self.locale = tmp_locale
-
end
-
yield
-
ensure
-
self.locale = current_locale if tmp_locale
-
end
-
-
# Merges the given locale, key and scope into a single array of keys.
-
# Splits keys that contain dots into multiple keys. Makes sure all
-
# keys are Symbols.
-
1
def normalize_keys(locale, key, scope, separator = nil)
-
2480
separator ||= I18n.default_separator
-
-
2480
keys = []
-
2480
keys.concat normalize_key(locale, separator)
-
2480
keys.concat normalize_key(scope, separator)
-
2480
keys.concat normalize_key(key, separator)
-
2480
keys
-
end
-
-
# making these private until Ruby 1.9.2 can send to protected methods again
-
# see http://redmine.ruby-lang.org/repositories/revision/ruby-19?rev=24280
-
1
private
-
-
# Any exceptions thrown in translate will be sent to the @@exception_handler
-
# which can be a Symbol, a Proc or any other Object unless they're forced to
-
# be raised or thrown (MissingTranslation).
-
#
-
# If exception_handler is a Symbol then it will simply be sent to I18n as
-
# a method call. A Proc will simply be called. In any other case the
-
# method #call will be called on the exception_handler object.
-
#
-
# Examples:
-
#
-
# I18n.exception_handler = :default_exception_handler # this is the default
-
# I18n.default_exception_handler(exception, locale, key, options) # will be called like this
-
#
-
# I18n.exception_handler = lambda { |*args| ... } # a lambda
-
# I18n.exception_handler.call(exception, locale, key, options) # will be called like this
-
#
-
# I18n.exception_handler = I18nExceptionHandler.new # an object
-
# I18n.exception_handler.call(exception, locale, key, options) # will be called like this
-
1
def handle_exception(handling, exception, locale, key, options)
-
1363
case handling
-
when :raise
-
raise(exception.respond_to?(:to_exception) ? exception.to_exception : exception)
-
when :throw
-
1348
throw :exception, exception
-
else
-
15
case handler = options[:exception_handler] || config.exception_handler
-
when Symbol
-
send(handler, exception, locale, key, options)
-
else
-
15
handler.call(exception, locale, key, options)
-
end
-
end
-
end
-
-
1
def normalize_key(key, separator)
-
7442
normalized_key_cache[separator][key] ||=
-
case key
-
when Array
-
3
key.map { |k| normalize_key(k, separator) }.flatten
-
else
-
286
keys = key.to_s.split(separator)
-
286
keys.delete('')
-
1508
keys.map! { |k| k.to_sym }
-
286
keys
-
end
-
end
-
-
1
def normalized_key_cache
-
7443
@normalized_key_cache ||= Hash.new { |h,k| h[k] = {} }
-
end
-
-
# DEPRECATED. Use I18n.normalize_keys instead.
-
1
def normalize_translation_keys(locale, key, scope, separator = nil)
-
puts "I18n.normalize_translation_keys is deprecated. Please use the class I18n.normalize_keys instead."
-
normalize_keys(locale, key, scope, separator)
-
end
-
-
# DEPRECATED. Please use the I18n::ExceptionHandler class instead.
-
1
def default_exception_handler(exception, locale, key, options)
-
puts "I18n.default_exception_handler is deprecated. Please use the class I18n::ExceptionHandler instead " +
-
"(an instance of which is set to I18n.exception_handler by default)."
-
exception.is_a?(MissingTranslation) ? exception.message : raise(exception)
-
end
-
1
}
-
end
-
1
module I18n
-
1
module Backend
-
1
autoload :Base, 'i18n/backend/base'
-
1
autoload :InterpolationCompiler, 'i18n/backend/interpolation_compiler'
-
1
autoload :Cache, 'i18n/backend/cache'
-
1
autoload :Cascade, 'i18n/backend/cascade'
-
1
autoload :Chain, 'i18n/backend/chain'
-
1
autoload :Fallbacks, 'i18n/backend/fallbacks'
-
1
autoload :Flatten, 'i18n/backend/flatten'
-
1
autoload :Gettext, 'i18n/backend/gettext'
-
1
autoload :KeyValue, 'i18n/backend/key_value'
-
1
autoload :Memoize, 'i18n/backend/memoize'
-
1
autoload :Metadata, 'i18n/backend/metadata'
-
1
autoload :Pluralization, 'i18n/backend/pluralization'
-
1
autoload :Simple, 'i18n/backend/simple'
-
1
autoload :Transliterator, 'i18n/backend/transliterator'
-
end
-
end
-
1
require 'yaml'
-
1
require 'i18n/core_ext/hash'
-
1
require 'i18n/core_ext/kernel/surpress_warnings'
-
-
1
module I18n
-
1
module Backend
-
1
module Base
-
1
include I18n::Backend::Transliterator
-
-
# Accepts a list of paths to translation files. Loads translations from
-
# plain Ruby (*.rb) or YAML files (*.yml). See #load_rb and #load_yml
-
# for details.
-
1
def load_translations(*filenames)
-
27
filenames = I18n.load_path if filenames.empty?
-
84
filenames.flatten.each { |filename| load_file(filename) }
-
end
-
-
# This method receives a locale, a data hash and options for storing translations.
-
# Should be implemented
-
1
def store_translations(locale, data, options = {})
-
raise NotImplementedError
-
end
-
-
1
def translate(locale, key, options = {})
-
2465
raise InvalidLocale.new(locale) unless locale
-
2465
entry = key && lookup(locale, key, options[:scope], options)
-
-
2465
if options.empty?
-
entry = resolve(locale, key, entry, options)
-
else
-
2465
count, default = options.values_at(:count, :default)
-
2465
values = options.except(*RESERVED_KEYS)
-
2465
entry = entry.nil? && default ?
-
default(locale, key, default, options) : resolve(locale, key, entry, options)
-
end
-
-
2465
throw(:exception, I18n::MissingTranslation.new(locale, key, options)) if entry.nil?
-
1102
entry = entry.dup if entry.is_a?(String)
-
-
1102
entry = pluralize(locale, entry, count) if count
-
1102
entry = interpolate(locale, entry, values) if values
-
1102
entry
-
end
-
-
# Acts the same as +strftime+, but uses a localized version of the
-
# format string. Takes a key from the date/time formats translations as
-
# a format argument (<em>e.g.</em>, <tt>:short</tt> in <tt>:'date.formats'</tt>).
-
1
def localize(locale, object, format = :default, options = {})
-
raise ArgumentError, "Object must be a Date, DateTime or Time object. #{object.inspect} given." unless object.respond_to?(:strftime)
-
-
if Symbol === format
-
key = format
-
type = object.respond_to?(:sec) ? 'time' : 'date'
-
options = options.merge(:raise => true, :object => object, :locale => locale)
-
format = I18n.t(:"#{type}.formats.#{key}", options)
-
end
-
-
# format = resolve(locale, object, format, options)
-
format = format.to_s.gsub(/%[aAbBp]/) do |match|
-
case match
-
when '%a' then I18n.t(:"date.abbr_day_names", :locale => locale, :format => format)[object.wday]
-
when '%A' then I18n.t(:"date.day_names", :locale => locale, :format => format)[object.wday]
-
when '%b' then I18n.t(:"date.abbr_month_names", :locale => locale, :format => format)[object.mon]
-
when '%B' then I18n.t(:"date.month_names", :locale => locale, :format => format)[object.mon]
-
when '%p' then I18n.t(:"time.#{object.hour < 12 ? :am : :pm}", :locale => locale, :format => format) if object.respond_to? :hour
-
end
-
end
-
-
object.strftime(format)
-
end
-
-
# Returns an array of locales for which translations are available
-
# ignoring the reserved translation meta data key :i18n.
-
1
def available_locales
-
raise NotImplementedError
-
end
-
-
1
def reload!
-
@skip_syntax_deprecation = false
-
end
-
-
1
protected
-
-
# The method which actually looks up for the translation in the store.
-
1
def lookup(locale, key, scope = [], options = {})
-
raise NotImplementedError
-
end
-
-
# Evaluates defaults.
-
# If given subject is an Array, it walks the array and returns the
-
# first translation that can be resolved. Otherwise it tries to resolve
-
# the translation directly.
-
1
def default(locale, object, subject, options = {})
-
3060
options = options.dup.reject { |key, value| key == :default }
-
774
case subject
-
when Array
-
subject.each do |item|
-
2105
result = resolve(locale, object, item, options) and return result
-
772
end and nil
-
else
-
2
resolve(locale, object, subject, options)
-
end
-
end
-
-
# Resolves a translation.
-
# If the given subject is a Symbol, it will be translated with the
-
# given options. If it is a Proc then it will be evaluated. All other
-
# subjects will be returned directly.
-
1
def resolve(locale, object, subject, options = {})
-
3798
return subject if options[:resolve] == false
-
3798
result = catch(:exception) do
-
3798
case subject
-
when Symbol
-
1589
I18n.translate(subject, options.merge(:locale => locale, :throw => true))
-
when Proc
-
date_or_time = options.delete(:object) || object
-
resolve(locale, object, subject.call(date_or_time, options))
-
else
-
2209
subject
-
end
-
end
-
3798
result unless result.is_a?(MissingTranslation)
-
end
-
-
# Picks a translation from an array according to English pluralization
-
# rules. It will pick the first translation if count is not equal to 1
-
# and the second translation if it is equal to 1. Other backends can
-
# implement more flexible or complex pluralization rules.
-
1
def pluralize(locale, entry, count)
-
588
return entry unless entry.is_a?(Hash) && count
-
-
key = :zero if count == 0 && entry.has_key?(:zero)
-
key ||= count == 1 ? :one : :other
-
raise InvalidPluralizationData.new(entry, count) unless entry.has_key?(key)
-
entry[key]
-
end
-
-
# Interpolates values into a given string.
-
#
-
# interpolate "file %{file} opened by %%{user}", :file => 'test.txt', :user => 'Mr. X'
-
# # => "file test.txt opened by %{user}"
-
1
def interpolate(locale, string, values = {})
-
1102
if string.is_a?(::String) && !values.empty?
-
1102
I18n.interpolate(string, values)
-
else
-
string
-
end
-
end
-
-
# Loads a single translations file by delegating to #load_rb or
-
# #load_yml depending on the file extension and directly merges the
-
# data to the existing translations. Raises I18n::UnknownFileType
-
# for all other file extensions.
-
1
def load_file(filename)
-
57
type = File.extname(filename).tr('.', '').downcase
-
57
raise UnknownFileType.new(type, filename) unless respond_to?(:"load_#{type}", true)
-
57
data = send(:"load_#{type}", filename)
-
57
raise InvalidLocaleData.new(filename) unless data.is_a?(Hash)
-
114
data.each { |locale, d| store_translations(locale, d || {}) }
-
end
-
-
# Loads a plain Ruby translations file. eval'ing the file must yield
-
# a Hash containing translation data with locales as toplevel keys.
-
1
def load_rb(filename)
-
eval(IO.read(filename), binding, filename)
-
end
-
-
# Loads a YAML translations file. The data must have locales as
-
# toplevel keys.
-
1
def load_yml(filename)
-
57
begin
-
57
YAML.load_file(filename)
-
rescue TypeError
-
nil
-
rescue SyntaxError
-
nil
-
end
-
end
-
end
-
end
-
end
-
1
module I18n
-
1
module Backend
-
# A simple backend that reads translations from YAML files and stores them in
-
# an in-memory hash. Relies on the Base backend.
-
#
-
# The implementation is provided by a Implementation module allowing to easily
-
# extend Simple backend's behavior by including modules. E.g.:
-
#
-
# module I18n::Backend::Pluralization
-
# def pluralize(*args)
-
# # extended pluralization logic
-
# super
-
# end
-
# end
-
#
-
# I18n::Backend::Simple.include(I18n::Backend::Pluralization)
-
1
class Simple
-
3
(class << self; self; end).class_eval { public :include }
-
-
1
module Implementation
-
1
include Base
-
-
1
def initialized?
-
2465
@initialized ||= false
-
end
-
-
# Stores translations for the given locale in memory.
-
# This uses a deep merge for the translations hash, so existing
-
# translations will be overwritten by new ones only at the deepest
-
# level of the hash.
-
1
def store_translations(locale, data, options = {})
-
86
locale = locale.to_sym
-
86
translations[locale] ||= {}
-
86
data = data.deep_symbolize_keys
-
86
translations[locale].deep_merge!(data)
-
end
-
-
# Get available locales from the translations hash
-
1
def available_locales
-
init_translations unless initialized?
-
translations.inject([]) do |locales, (locale, data)|
-
locales << locale unless (data.keys - [:i18n]).empty?
-
locales
-
end
-
end
-
-
# Clean up translations hash and set initialized to false on reload!
-
1
def reload!
-
@initialized = false
-
@translations = nil
-
super
-
end
-
-
1
protected
-
-
1
def init_translations
-
27
load_translations
-
27
@initialized = true
-
end
-
-
1
def translations
-
2637
@translations ||= {}
-
end
-
-
# Looks up a translation from the translations hash. Returns nil if
-
# eiher key is nil, or locale, scope or key do not exist as a key in the
-
# nested translations hash. Splits keys or scopes containing dots
-
# into multiple keys, i.e. <tt>currency.format</tt> is regarded the same as
-
# <tt>%w(currency format)</tt>.
-
1
def lookup(locale, key, scope = [], options = {})
-
2465
init_translations unless initialized?
-
2465
keys = I18n.normalize_keys(locale, key, scope, options[:separator])
-
-
2465
keys.inject(translations) do |result, _key|
-
8506
_key = _key.to_sym
-
8506
return nil unless result.is_a?(Hash) && result.has_key?(_key)
-
6384
result = result[_key]
-
6384
result = resolve(locale, _key, result, options.merge(:scope => nil)) if result.is_a?(Symbol)
-
6384
result
-
end
-
end
-
end
-
-
1
include Implementation
-
end
-
end
-
end
-
# encoding: utf-8
-
1
module I18n
-
1
module Backend
-
1
module Transliterator
-
1
DEFAULT_REPLACEMENT_CHAR = "?"
-
-
# Given a locale and a UTF-8 string, return the locale's ASCII
-
# approximation for the string.
-
1
def transliterate(locale, string, replacement = nil)
-
@transliterators ||= {}
-
@transliterators[locale] ||= Transliterator.get I18n.t(:'i18n.transliterate.rule',
-
:locale => locale, :resolve => false, :default => {})
-
@transliterators[locale].transliterate(string, replacement)
-
end
-
-
# Get a transliterator instance.
-
1
def self.get(rule = nil)
-
if !rule || rule.kind_of?(Hash)
-
HashTransliterator.new(rule)
-
elsif rule.kind_of? Proc
-
ProcTransliterator.new(rule)
-
else
-
raise I18n::ArgumentError, "Transliteration rule must be a proc or a hash."
-
end
-
end
-
-
# A transliterator which accepts a Proc as its transliteration rule.
-
1
class ProcTransliterator
-
1
def initialize(rule)
-
@rule = rule
-
end
-
-
1
def transliterate(string, replacement = nil)
-
@rule.call(string)
-
end
-
end
-
-
# A transliterator which accepts a Hash of characters as its translation
-
# rule.
-
1
class HashTransliterator
-
1
DEFAULT_APPROXIMATIONS = {
-
"À"=>"A", "Á"=>"A", "Â"=>"A", "Ã"=>"A", "Ä"=>"A", "Å"=>"A", "Æ"=>"AE",
-
"Ç"=>"C", "È"=>"E", "É"=>"E", "Ê"=>"E", "Ë"=>"E", "Ì"=>"I", "Í"=>"I",
-
"Î"=>"I", "Ï"=>"I", "Ð"=>"D", "Ñ"=>"N", "Ò"=>"O", "Ó"=>"O", "Ô"=>"O",
-
"Õ"=>"O", "Ö"=>"O", "×"=>"x", "Ø"=>"O", "Ù"=>"U", "Ú"=>"U", "Û"=>"U",
-
"Ü"=>"U", "Ý"=>"Y", "Þ"=>"Th", "ß"=>"ss", "à"=>"a", "á"=>"a", "â"=>"a",
-
"ã"=>"a", "ä"=>"a", "å"=>"a", "æ"=>"ae", "ç"=>"c", "è"=>"e", "é"=>"e",
-
"ê"=>"e", "ë"=>"e", "ì"=>"i", "í"=>"i", "î"=>"i", "ï"=>"i", "ð"=>"d",
-
"ñ"=>"n", "ò"=>"o", "ó"=>"o", "ô"=>"o", "õ"=>"o", "ö"=>"o", "ø"=>"o",
-
"ù"=>"u", "ú"=>"u", "û"=>"u", "ü"=>"u", "ý"=>"y", "þ"=>"th", "ÿ"=>"y",
-
"Ā"=>"A", "ā"=>"a", "Ă"=>"A", "ă"=>"a", "Ą"=>"A", "ą"=>"a", "Ć"=>"C",
-
"ć"=>"c", "Ĉ"=>"C", "ĉ"=>"c", "Ċ"=>"C", "ċ"=>"c", "Č"=>"C", "č"=>"c",
-
"Ď"=>"D", "ď"=>"d", "Đ"=>"D", "đ"=>"d", "Ē"=>"E", "ē"=>"e", "Ĕ"=>"E",
-
"ĕ"=>"e", "Ė"=>"E", "ė"=>"e", "Ę"=>"E", "ę"=>"e", "Ě"=>"E", "ě"=>"e",
-
"Ĝ"=>"G", "ĝ"=>"g", "Ğ"=>"G", "ğ"=>"g", "Ġ"=>"G", "ġ"=>"g", "Ģ"=>"G",
-
"ģ"=>"g", "Ĥ"=>"H", "ĥ"=>"h", "Ħ"=>"H", "ħ"=>"h", "Ĩ"=>"I", "ĩ"=>"i",
-
"Ī"=>"I", "ī"=>"i", "Ĭ"=>"I", "ĭ"=>"i", "Į"=>"I", "į"=>"i", "İ"=>"I",
-
"ı"=>"i", "IJ"=>"IJ", "ij"=>"ij", "Ĵ"=>"J", "ĵ"=>"j", "Ķ"=>"K", "ķ"=>"k",
-
"ĸ"=>"k", "Ĺ"=>"L", "ĺ"=>"l", "Ļ"=>"L", "ļ"=>"l", "Ľ"=>"L", "ľ"=>"l",
-
"Ŀ"=>"L", "ŀ"=>"l", "Ł"=>"L", "ł"=>"l", "Ń"=>"N", "ń"=>"n", "Ņ"=>"N",
-
"ņ"=>"n", "Ň"=>"N", "ň"=>"n", "ʼn"=>"'n", "Ŋ"=>"NG", "ŋ"=>"ng",
-
"Ō"=>"O", "ō"=>"o", "Ŏ"=>"O", "ŏ"=>"o", "Ő"=>"O", "ő"=>"o", "Œ"=>"OE",
-
"œ"=>"oe", "Ŕ"=>"R", "ŕ"=>"r", "Ŗ"=>"R", "ŗ"=>"r", "Ř"=>"R", "ř"=>"r",
-
"Ś"=>"S", "ś"=>"s", "Ŝ"=>"S", "ŝ"=>"s", "Ş"=>"S", "ş"=>"s", "Š"=>"S",
-
"š"=>"s", "Ţ"=>"T", "ţ"=>"t", "Ť"=>"T", "ť"=>"t", "Ŧ"=>"T", "ŧ"=>"t",
-
"Ũ"=>"U", "ũ"=>"u", "Ū"=>"U", "ū"=>"u", "Ŭ"=>"U", "ŭ"=>"u", "Ů"=>"U",
-
"ů"=>"u", "Ű"=>"U", "ű"=>"u", "Ų"=>"U", "ų"=>"u", "Ŵ"=>"W", "ŵ"=>"w",
-
"Ŷ"=>"Y", "ŷ"=>"y", "Ÿ"=>"Y", "Ź"=>"Z", "ź"=>"z", "Ż"=>"Z", "ż"=>"z",
-
"Ž"=>"Z", "ž"=>"z"
-
}
-
-
1
def initialize(rule = nil)
-
@rule = rule
-
add DEFAULT_APPROXIMATIONS
-
add rule if rule
-
end
-
-
1
def transliterate(string, replacement = nil)
-
string.gsub(/[^\x00-\x7f]/u) do |char|
-
approximations[char] || replacement || DEFAULT_REPLACEMENT_CHAR
-
end
-
end
-
-
1
private
-
-
1
def approximations
-
@approximations ||= {}
-
end
-
-
# Add transliteration rules to the approximations hash.
-
1
def add(hash)
-
hash.keys.each {|key| hash[key.to_s] = hash.delete(key).to_s}
-
approximations.merge! hash
-
end
-
end
-
end
-
end
-
end
-
1
module I18n
-
1
class Config
-
# The only configuration value that is not global and scoped to thread is :locale.
-
# It defaults to the default_locale.
-
1
def locale
-
876
@locale ||= default_locale
-
end
-
-
# Sets the current locale pseudo-globally, i.e. in the Thread.current hash.
-
1
def locale=(locale)
-
@locale = locale.to_sym rescue nil
-
end
-
-
# Returns the current backend. Defaults to +Backend::Simple+.
-
1
def backend
-
2507
@@backend ||= Backend::Simple.new
-
end
-
-
# Sets the current backend. Used to set a custom backend.
-
1
def backend=(backend)
-
45
@@backend = backend
-
end
-
-
# Returns the current default locale. Defaults to :'en'
-
1
def default_locale
-
1
@@default_locale ||= :en
-
end
-
-
# Sets the current default locale. Used to set a custom default locale.
-
1
def default_locale=(locale)
-
@@default_locale = locale.to_sym rescue nil
-
end
-
-
# Returns an array of locales for which translations are available.
-
# Unless you explicitely set these through I18n.available_locales=
-
# the call will be delegated to the backend.
-
1
def available_locales
-
@@available_locales ||= nil
-
@@available_locales || backend.available_locales
-
end
-
-
# Sets the available locales.
-
1
def available_locales=(locales)
-
@@available_locales = Array(locales).map { |locale| locale.to_sym }
-
@@available_locales = nil if @@available_locales.empty?
-
end
-
-
# Returns the current default scope separator. Defaults to '.'
-
1
def default_separator
-
2480
@@default_separator ||= '.'
-
end
-
-
# Sets the current default scope separator.
-
1
def default_separator=(separator)
-
@@default_separator = separator
-
end
-
-
# Return the current exception handler. Defaults to :default_exception_handler.
-
1
def exception_handler
-
15
@@exception_handler ||= ExceptionHandler.new
-
end
-
-
# Sets the exception handler.
-
1
def exception_handler=(exception_handler)
-
@@exception_handler = exception_handler
-
end
-
-
# Allow clients to register paths providing translation data sources. The
-
# backend defines acceptable sources.
-
#
-
# E.g. the provided SimpleBackend accepts a list of paths to translation
-
# files which are either named *.rb and contain plain Ruby Hashes or are
-
# named *.yml and contain YAML data. So for the SimpleBackend clients may
-
# register translation files like this:
-
# I18n.load_path << 'path/to/locale/en.yml'
-
1
def load_path
-
69
@@load_path ||= []
-
end
-
-
# Sets the load path instance. Custom implementations are expected to
-
# behave like a Ruby Array.
-
1
def load_path=(load_path)
-
@@load_path = load_path
-
end
-
end
-
end
-
1
class Hash
-
def slice(*keep_keys)
-
h = {}
-
keep_keys.each { |key| h[key] = fetch(key) }
-
h
-
1
end unless Hash.method_defined?(:slice)
-
-
def except(*less_keys)
-
slice(*keys - less_keys)
-
1
end unless Hash.method_defined?(:except)
-
-
def deep_symbolize_keys
-
inject({}) { |result, (key, value)|
-
value = value.deep_symbolize_keys if value.is_a?(Hash)
-
result[(key.to_sym rescue key) || key] = value
-
result
-
}
-
1
end unless Hash.method_defined?(:deep_symbolize_keys)
-
-
# deep_merge_hash! by Stefan Rusterholz, see http://www.ruby-forum.com/topic/142809
-
1
MERGER = proc do |key, v1, v2|
-
Hash === v1 && Hash === v2 ? v1.merge(v2, &MERGER) : v2
-
end
-
-
def deep_merge!(data)
-
merge!(data, &MERGER)
-
1
end unless Hash.method_defined?(:deep_merge!)
-
end
-
-
1
module Kernel
-
1
def suppress_warnings
-
original_verbosity = $VERBOSE
-
$VERBOSE = nil
-
result = yield
-
$VERBOSE = original_verbosity
-
result
-
end
-
end
-
1
module I18n
-
# Handles exceptions raised in the backend. All exceptions except for
-
# MissingTranslationData exceptions are re-thrown. When a MissingTranslationData
-
# was caught the handler returns an error message string containing the key/scope.
-
# Note that the exception handler is not called when the option :throw was given.
-
1
class ExceptionHandler
-
include Module.new {
-
1
def call(exception, locale, key, options)
-
15
if exception.is_a?(MissingTranslation)
-
15
options[:rescue_format] == :html ? exception.html_message : exception.message
-
elsif exception.is_a?(Exception)
-
raise exception
-
else
-
throw :exception, exception
-
end
-
end
-
1
}
-
end
-
-
1
class ArgumentError < ::ArgumentError; end
-
-
1
class InvalidLocale < ArgumentError
-
1
attr_reader :locale
-
1
def initialize(locale)
-
@locale = locale
-
super "#{locale.inspect} is not a valid locale"
-
end
-
end
-
-
1
class InvalidLocaleData < ArgumentError
-
1
attr_reader :filename
-
1
def initialize(filename)
-
@filename = filename
-
super "can not load translations from #{filename}, expected it to return a hash, but does not"
-
end
-
end
-
-
1
class MissingTranslation
-
1
module Base
-
1
attr_reader :locale, :key, :options
-
-
1
def initialize(locale, key, options = nil)
-
1363
@key, @locale, @options = key, locale, options.dup || {}
-
4639
options.each { |k, v| self.options[k] = v.inspect if v.is_a?(Proc) }
-
end
-
-
1
def html_message
-
key = keys.last.to_s.gsub('_', ' ').gsub(/\b('?[a-z])/) { $1.capitalize }
-
%(<span class="translation_missing" title="translation missing: #{keys.join('.')}">#{key}</span>)
-
end
-
-
1
def keys
-
@keys ||= I18n.normalize_keys(locale, key, options[:scope]).tap do |keys|
-
15
keys << 'no key' if keys.size < 2
-
15
end
-
end
-
-
1
def message
-
15
"translation missing: #{keys.join('.')}"
-
end
-
1
alias :to_s :message
-
-
1
def to_exception
-
MissingTranslationData.new(locale, key, options)
-
end
-
end
-
-
1
include Base
-
end
-
-
1
class MissingTranslationData < ArgumentError
-
1
include MissingTranslation::Base
-
end
-
-
1
class InvalidPluralizationData < ArgumentError
-
1
attr_reader :entry, :count
-
1
def initialize(entry, count)
-
@entry, @count = entry, count
-
super "translation data #{entry.inspect} can not be used with :count => #{count}"
-
end
-
end
-
-
1
class MissingInterpolationArgument < ArgumentError
-
1
attr_reader :values, :string
-
1
def initialize(values, string)
-
@values, @string = values, string
-
super "missing interpolation argument in #{string.inspect} (#{values.inspect} given)"
-
end
-
end
-
-
1
class ReservedInterpolationKey < ArgumentError
-
1
attr_reader :key, :string
-
1
def initialize(key, string)
-
@key, @string = key, string
-
super "reserved key #{key.inspect} used in #{string.inspect}"
-
end
-
end
-
-
1
class UnknownFileType < ArgumentError
-
1
attr_reader :type, :filename
-
1
def initialize(type, filename)
-
@type, @filename = type, filename
-
super "can not load translations from #{filename}, the file type #{type} is not known"
-
end
-
end
-
end
-
# heavily based on Masao Mutoh's gettext String interpolation extension
-
# http://github.com/mutoh/gettext/blob/f6566738b981fe0952548c421042ad1e0cdfb31e/lib/gettext/core_ext/string.rb
-
-
1
module I18n
-
1
INTERPOLATION_PATTERN = Regexp.union(
-
/%%/,
-
/%\{(\w+)\}/, # matches placeholders like "%{foo}"
-
/%<(\w+)>(.*?\d*\.?\d*[bBdiouxXeEfgGcps])/ # matches placeholders like "%<foo>.d"
-
)
-
-
1
class << self
-
1
def interpolate(string, values)
-
1102
raise ReservedInterpolationKey.new($1.to_sym, string) if string =~ RESERVED_KEYS_PATTERN
-
1102
raise ArgumentError.new('Interpolation values must be a Hash.') unless values.kind_of?(Hash)
-
1102
interpolate_hash(string, values)
-
end
-
-
1
def interpolate_hash(string, values)
-
1102
string.gsub(INTERPOLATION_PATTERN) do |match|
-
147
if match == '%%'
-
'%'
-
else
-
147
key = ($1 || $2).to_sym
-
147
value = values.key?(key) ? values[key] : raise(MissingInterpolationArgument.new(values, string))
-
147
value = value.call(values) if value.respond_to?(:call)
-
147
$3 ? sprintf("%#{$3}", value) : value
-
end
-
end
-
end
-
end
-
end
-
1
module I18n
-
1
VERSION = "0.6.1"
-
end
-
##
-
# = JavaScript Object Notation (JSON)
-
#
-
# JSON is a lightweight data-interchange format. It is easy for us
-
# humans to read and write. Plus, equally simple for machines to generate or parse.
-
# JSON is completely language agnostic, making it the ideal interchange format.
-
#
-
# Built on two universally available structures:
-
# 1. A collection of name/value pairs. Often referred to as an _object_, hash table, record, struct, keyed list, or associative array.
-
# 2. An ordered list of values. More commonly called an _array_, vector, sequence or list.
-
#
-
# To read more about JSON visit: http://json.org
-
#
-
# == Parsing JSON
-
#
-
# To parse a JSON string received by another application or generated within
-
# your existing application:
-
#
-
# require 'json'
-
#
-
# my_hash = JSON.parse('{"hello": "goodbye"}')
-
# puts my_hash["hello"] => "goodbye"
-
#
-
# Notice the extra quotes <tt>''</tt> around the hash notation. Ruby expects
-
# the argument to be a string and can't convert objects like a hash or array.
-
#
-
# Ruby converts your string into a hash
-
#
-
# == Generating JSON
-
#
-
# Creating a JSON string for communication or serialization is
-
# just as simple.
-
#
-
# require 'json'
-
#
-
# my_hash = {:hello => "goodbye"}
-
# puts JSON.generate(my_hash) => "{\"hello\":\"goodbye\"}"
-
#
-
# Or an alternative way:
-
#
-
# require 'json'
-
# puts {:hello => "goodbye"}.to_json => "{\"hello\":\"goodbye\"}"
-
#
-
# <tt>JSON.generate</tt> only allows objects or arrays to be converted
-
# to JSON syntax. <tt>to_json</tt>, however, accepts many Ruby classes
-
# even though it acts only as a method for serialization:
-
#
-
# require 'json'
-
#
-
# 1.to_json => "1"
-
#
-
-
1
require 'json/common'
-
1
module JSON
-
1
require 'json/version'
-
-
1
begin
-
1
require 'json/ext'
-
rescue LoadError
-
require 'json/pure'
-
end
-
end
-
1
require 'json/version'
-
1
require 'json/generic_object'
-
-
1
module JSON
-
1
class << self
-
# If _object_ is string-like, parse the string and return the parsed result
-
# as a Ruby data structure. Otherwise generate a JSON text from the Ruby
-
# data structure object and return it.
-
#
-
# The _opts_ argument is passed through to generate/parse respectively. See
-
# generate and parse for their documentation.
-
1
def [](object, opts = {})
-
if object.respond_to? :to_str
-
JSON.parse(object.to_str, opts)
-
else
-
JSON.generate(object, opts)
-
end
-
end
-
-
# Returns the JSON parser class that is used by JSON. This is either
-
# JSON::Ext::Parser or JSON::Pure::Parser.
-
1
attr_reader :parser
-
-
# Set the JSON parser class _parser_ to be used by JSON.
-
1
def parser=(parser) # :nodoc:
-
1
@parser = parser
-
1
remove_const :Parser if JSON.const_defined_in?(self, :Parser)
-
1
const_set :Parser, parser
-
end
-
-
# Return the constant located at _path_. The format of _path_ has to be
-
# either ::A::B::C or A::B::C. In any case, A has to be located at the top
-
# level (absolute namespace path?). If there doesn't exist a constant at
-
# the given path, an ArgumentError is raised.
-
1
def deep_const_get(path) # :nodoc:
-
10
path.to_s.split(/::/).inject(Object) do |p, c|
-
case
-
when c.empty? then p
-
10
when JSON.const_defined_in?(p, c) then p.const_get(c)
-
else
-
begin
-
p.const_missing(c)
-
rescue NameError => e
-
raise ArgumentError, "can't get const #{path}: #{e}"
-
end
-
10
end
-
end
-
end
-
-
# Set the module _generator_ to be used by JSON.
-
1
def generator=(generator) # :nodoc:
-
1
old, $VERBOSE = $VERBOSE, nil
-
1
@generator = generator
-
1
generator_methods = generator::GeneratorMethods
-
1
for const in generator_methods.constants
-
10
klass = deep_const_get(const)
-
10
modul = generator_methods.const_get(const)
-
10
klass.class_eval do
-
10
instance_methods(false).each do |m|
-
493
m.to_s == 'to_json' and remove_method m
-
end
-
10
include modul
-
end
-
end
-
1
self.state = generator::State
-
1
const_set :State, self.state
-
1
const_set :SAFE_STATE_PROTOTYPE, State.new
-
1
const_set :FAST_STATE_PROTOTYPE, State.new(
-
:indent => '',
-
:space => '',
-
:object_nl => "",
-
:array_nl => "",
-
:max_nesting => false
-
)
-
1
const_set :PRETTY_STATE_PROTOTYPE, State.new(
-
:indent => ' ',
-
:space => ' ',
-
:object_nl => "\n",
-
:array_nl => "\n"
-
)
-
ensure
-
1
$VERBOSE = old
-
end
-
-
# Returns the JSON generator module that is used by JSON. This is
-
# either JSON::Ext::Generator or JSON::Pure::Generator.
-
1
attr_reader :generator
-
-
# Returns the JSON generator state class that is used by JSON. This is
-
# either JSON::Ext::Generator::State or JSON::Pure::Generator::State.
-
1
attr_accessor :state
-
-
# This is create identifier, which is used to decide if the _json_create_
-
# hook of a class should be called. It defaults to 'json_class'.
-
1
attr_accessor :create_id
-
end
-
1
self.create_id = 'json_class'
-
-
1
NaN = 0.0/0
-
-
1
Infinity = 1.0/0
-
-
1
MinusInfinity = -Infinity
-
-
# The base exception for JSON errors.
-
1
class JSONError < StandardError
-
1
def self.wrap(exception)
-
obj = new("Wrapped(#{exception.class}): #{exception.message.inspect}")
-
obj.set_backtrace exception.backtrace
-
obj
-
end
-
end
-
-
# This exception is raised if a parser error occurs.
-
1
class ParserError < JSONError; end
-
-
# This exception is raised if the nesting of parsed data structures is too
-
# deep.
-
1
class NestingError < ParserError; end
-
-
# :stopdoc:
-
1
class CircularDatastructure < NestingError; end
-
# :startdoc:
-
-
# This exception is raised if a generator or unparser error occurs.
-
1
class GeneratorError < JSONError; end
-
# For backwards compatibility
-
1
UnparserError = GeneratorError
-
-
# This exception is raised if the required unicode support is missing on the
-
# system. Usually this means that the iconv library is not installed.
-
1
class MissingUnicodeSupport < JSONError; end
-
-
1
module_function
-
-
# Parse the JSON document _source_ into a Ruby data structure and return it.
-
#
-
# _opts_ can have the following
-
# keys:
-
# * *max_nesting*: The maximum depth of nesting allowed in the parsed data
-
# structures. Disable depth checking with :max_nesting => false. It defaults
-
# to 19.
-
# * *allow_nan*: If set to true, allow NaN, Infinity and -Infinity in
-
# defiance of RFC 4627 to be parsed by the Parser. This option defaults
-
# to false.
-
# * *symbolize_names*: If set to true, returns symbols for the names
-
# (keys) in a JSON object. Otherwise strings are returned. Strings are
-
# the default.
-
# * *create_additions*: If set to false, the Parser doesn't create
-
# additions even if a matching class and create_id was found. This option
-
# defaults to true.
-
# * *object_class*: Defaults to Hash
-
# * *array_class*: Defaults to Array
-
1
def parse(source, opts = {})
-
90
Parser.new(source, opts).parse
-
end
-
-
# Parse the JSON document _source_ into a Ruby data structure and return it.
-
# The bang version of the parse method defaults to the more dangerous values
-
# for the _opts_ hash, so be sure only to parse trusted _source_ documents.
-
#
-
# _opts_ can have the following keys:
-
# * *max_nesting*: The maximum depth of nesting allowed in the parsed data
-
# structures. Enable depth checking with :max_nesting => anInteger. The parse!
-
# methods defaults to not doing max depth checking: This can be dangerous
-
# if someone wants to fill up your stack.
-
# * *allow_nan*: If set to true, allow NaN, Infinity, and -Infinity in
-
# defiance of RFC 4627 to be parsed by the Parser. This option defaults
-
# to true.
-
# * *create_additions*: If set to false, the Parser doesn't create
-
# additions even if a matching class and create_id was found. This option
-
# defaults to true.
-
1
def parse!(source, opts = {})
-
opts = {
-
:max_nesting => false,
-
:allow_nan => true
-
}.update(opts)
-
Parser.new(source, opts).parse
-
end
-
-
# Generate a JSON document from the Ruby data structure _obj_ and return
-
# it. _state_ is * a JSON::State object,
-
# * or a Hash like object (responding to to_hash),
-
# * an object convertible into a hash by a to_h method,
-
# that is used as or to configure a State object.
-
#
-
# It defaults to a state object, that creates the shortest possible JSON text
-
# in one line, checks for circular data structures and doesn't allow NaN,
-
# Infinity, and -Infinity.
-
#
-
# A _state_ hash can have the following keys:
-
# * *indent*: a string used to indent levels (default: ''),
-
# * *space*: a string that is put after, a : or , delimiter (default: ''),
-
# * *space_before*: a string that is put before a : pair delimiter (default: ''),
-
# * *object_nl*: a string that is put at the end of a JSON object (default: ''),
-
# * *array_nl*: a string that is put at the end of a JSON array (default: ''),
-
# * *allow_nan*: true if NaN, Infinity, and -Infinity should be
-
# generated, otherwise an exception is thrown if these values are
-
# encountered. This options defaults to false.
-
# * *max_nesting*: The maximum depth of nesting allowed in the data
-
# structures from which JSON is to be generated. Disable depth checking
-
# with :max_nesting => false, it defaults to 19.
-
#
-
# See also the fast_generate for the fastest creation method with the least
-
# amount of sanity checks, and the pretty_generate method for some
-
# defaults for pretty output.
-
1
def generate(obj, opts = nil)
-
46
if State === opts
-
state, opts = opts, nil
-
else
-
46
state = SAFE_STATE_PROTOTYPE.dup
-
end
-
46
if opts
-
46
if opts.respond_to? :to_hash
-
46
opts = opts.to_hash
-
elsif opts.respond_to? :to_h
-
opts = opts.to_h
-
else
-
raise TypeError, "can't convert #{opts.class} into Hash"
-
end
-
46
state = state.configure(opts)
-
end
-
46
state.generate(obj)
-
end
-
-
# :stopdoc:
-
# I want to deprecate these later, so I'll first be silent about them, and
-
# later delete them.
-
1
alias unparse generate
-
1
module_function :unparse
-
# :startdoc:
-
-
# Generate a JSON document from the Ruby data structure _obj_ and return it.
-
# This method disables the checks for circles in Ruby objects.
-
#
-
# *WARNING*: Be careful not to pass any Ruby data structures with circles as
-
# _obj_ argument because this will cause JSON to go into an infinite loop.
-
1
def fast_generate(obj, opts = nil)
-
if State === opts
-
state, opts = opts, nil
-
else
-
state = FAST_STATE_PROTOTYPE.dup
-
end
-
if opts
-
if opts.respond_to? :to_hash
-
opts = opts.to_hash
-
elsif opts.respond_to? :to_h
-
opts = opts.to_h
-
else
-
raise TypeError, "can't convert #{opts.class} into Hash"
-
end
-
state.configure(opts)
-
end
-
state.generate(obj)
-
end
-
-
# :stopdoc:
-
# I want to deprecate these later, so I'll first be silent about them, and later delete them.
-
1
alias fast_unparse fast_generate
-
1
module_function :fast_unparse
-
# :startdoc:
-
-
# Generate a JSON document from the Ruby data structure _obj_ and return it.
-
# The returned document is a prettier form of the document returned by
-
# #unparse.
-
#
-
# The _opts_ argument can be used to configure the generator. See the
-
# generate method for a more detailed explanation.
-
1
def pretty_generate(obj, opts = nil)
-
if State === opts
-
state, opts = opts, nil
-
else
-
state = PRETTY_STATE_PROTOTYPE.dup
-
end
-
if opts
-
if opts.respond_to? :to_hash
-
opts = opts.to_hash
-
elsif opts.respond_to? :to_h
-
opts = opts.to_h
-
else
-
raise TypeError, "can't convert #{opts.class} into Hash"
-
end
-
state.configure(opts)
-
end
-
state.generate(obj)
-
end
-
-
# :stopdoc:
-
# I want to deprecate these later, so I'll first be silent about them, and later delete them.
-
1
alias pretty_unparse pretty_generate
-
1
module_function :pretty_unparse
-
# :startdoc:
-
-
1
class << self
-
# The global default options for the JSON.load method:
-
# :max_nesting: false
-
# :allow_nan: true
-
# :quirks_mode: true
-
1
attr_accessor :load_default_options
-
end
-
1
self.load_default_options = {
-
:max_nesting => false,
-
:allow_nan => true,
-
:quirks_mode => true,
-
}
-
-
# Load a ruby data structure from a JSON _source_ and return it. A source can
-
# either be a string-like object, an IO-like object, or an object responding
-
# to the read method. If _proc_ was given, it will be called with any nested
-
# Ruby object as an argument recursively in depth first order. The default
-
# options for the parser can be changed via the load_default_options method.
-
#
-
# This method is part of the implementation of the load/dump interface of
-
# Marshal and YAML.
-
1
def load(source, proc = nil)
-
87
opts = load_default_options
-
87
if source.respond_to? :to_str
-
64
source = source.to_str
-
elsif source.respond_to? :to_io
-
source = source.to_io.read
-
elsif source.respond_to?(:read)
-
source = source.read
-
end
-
87
if opts[:quirks_mode] && (source.nil? || source.empty?)
-
44
source = 'null'
-
end
-
87
result = parse(source, opts)
-
87
recurse_proc(result, &proc) if proc
-
87
result
-
end
-
-
# Recursively calls passed _Proc_ if the parsed data structure is an _Array_ or _Hash_
-
1
def recurse_proc(result, &proc)
-
case result
-
when Array
-
result.each { |x| recurse_proc x, &proc }
-
proc.call result
-
when Hash
-
result.each { |x, y| recurse_proc x, &proc; recurse_proc y, &proc }
-
proc.call result
-
else
-
proc.call result
-
end
-
end
-
-
1
alias restore load
-
1
module_function :restore
-
-
1
class << self
-
# The global default options for the JSON.dump method:
-
# :max_nesting: false
-
# :allow_nan: true
-
# :quirks_mode: true
-
1
attr_accessor :dump_default_options
-
end
-
1
self.dump_default_options = {
-
:max_nesting => false,
-
:allow_nan => true,
-
:quirks_mode => true,
-
}
-
-
# Dumps _obj_ as a JSON string, i.e. calls generate on the object and returns
-
# the result.
-
#
-
# If anIO (an IO-like object or an object that responds to the write method)
-
# was given, the resulting JSON is written to it.
-
#
-
# If the number of nested arrays or objects exceeds _limit_, an ArgumentError
-
# exception is raised. This argument is similar (but not exactly the
-
# same!) to the _limit_ argument in Marshal.dump.
-
#
-
# The default options for the generator can be changed via the
-
# dump_default_options method.
-
#
-
# This method is part of the implementation of the load/dump interface of
-
# Marshal and YAML.
-
1
def dump(obj, anIO = nil, limit = nil)
-
46
if anIO and limit.nil?
-
anIO = anIO.to_io if anIO.respond_to?(:to_io)
-
unless anIO.respond_to?(:write)
-
limit = anIO
-
anIO = nil
-
end
-
end
-
46
opts = JSON.dump_default_options
-
46
limit and opts.update(:max_nesting => limit)
-
46
result = generate(obj, opts)
-
46
if anIO
-
anIO.write result
-
anIO
-
else
-
46
result
-
end
-
rescue JSON::NestingError
-
raise ArgumentError, "exceed depth limit"
-
end
-
-
# Swap consecutive bytes of _string_ in place.
-
1
def self.swap!(string) # :nodoc:
-
0.upto(string.size / 2) do |i|
-
break unless string[2 * i + 1]
-
string[2 * i], string[2 * i + 1] = string[2 * i + 1], string[2 * i]
-
end
-
string
-
end
-
-
# Shortuct for iconv.
-
if ::String.method_defined?(:encode) &&
-
# XXX Rubinius doesn't support ruby 1.9 encoding yet
-
1
defined?(RUBY_ENGINE) && RUBY_ENGINE != 'rbx'
-
then
-
# Encodes string using Ruby's _String.encode_
-
1
def self.iconv(to, from, string)
-
string.encode(to, from)
-
end
-
else
-
require 'iconv'
-
# Encodes string using _iconv_ library
-
def self.iconv(to, from, string)
-
Iconv.conv(to, from, string)
-
end
-
end
-
-
1
if ::Object.method(:const_defined?).arity == 1
-
def self.const_defined_in?(modul, constant)
-
modul.const_defined?(constant)
-
end
-
else
-
1
def self.const_defined_in?(modul, constant)
-
11
modul.const_defined?(constant, false)
-
end
-
end
-
end
-
-
1
module ::Kernel
-
1
private
-
-
# Outputs _objs_ to STDOUT as JSON strings in the shortest form, that is in
-
# one line.
-
1
def j(*objs)
-
objs.each do |obj|
-
puts JSON::generate(obj, :allow_nan => true, :max_nesting => false)
-
end
-
nil
-
end
-
-
# Ouputs _objs_ to STDOUT as JSON strings in a pretty format, with
-
# indentation and over many lines.
-
1
def jj(*objs)
-
objs.each do |obj|
-
puts JSON::pretty_generate(obj, :allow_nan => true, :max_nesting => false)
-
end
-
nil
-
end
-
-
# If _object_ is string-like, parse the string and return the parsed result as
-
# a Ruby data structure. Otherwise, generate a JSON text from the Ruby data
-
# structure object and return it.
-
#
-
# The _opts_ argument is passed through to generate/parse respectively. See
-
# generate and parse for their documentation.
-
1
def JSON(object, *args)
-
if object.respond_to? :to_str
-
JSON.parse(object.to_str, args.first)
-
else
-
JSON.generate(object, args.first)
-
end
-
end
-
end
-
-
# Extends any Class to include _json_creatable?_ method.
-
1
class ::Class
-
# Returns true if this class can be used to create an instance
-
# from a serialised JSON string. The class has to implement a class
-
# method _json_create_ that expects a hash as first parameter. The hash
-
# should include the required data.
-
1
def json_creatable?
-
respond_to?(:json_create)
-
end
-
end
-
1
if ENV['SIMPLECOV_COVERAGE'].to_i == 1
-
require 'simplecov'
-
SimpleCov.start do
-
add_filter "/tests/"
-
end
-
end
-
1
require 'json/common'
-
-
1
module JSON
-
# This module holds all the modules/classes that implement JSON's
-
# functionality as C extensions.
-
1
module Ext
-
1
require 'json/ext/parser'
-
1
require 'json/ext/generator'
-
1
$DEBUG and warn "Using Ext extension for JSON."
-
1
JSON.parser = Parser
-
1
JSON.generator = Generator
-
end
-
-
1
JSON_LOADED = true unless defined?(::JSON::JSON_LOADED)
-
end
-
1
require 'ostruct'
-
-
1
module JSON
-
1
class GenericObject < OpenStruct
-
1
class << self
-
1
alias [] new
-
-
1
def json_create(data)
-
data = data.dup
-
data.delete JSON.create_id
-
self[data]
-
end
-
end
-
-
1
def to_hash
-
table
-
end
-
-
1
def [](name)
-
table[name.to_sym]
-
end
-
-
1
def []=(name, value)
-
__send__ "#{name}=", value
-
end
-
-
1
def |(other)
-
self.class[other.to_hash.merge(to_hash)]
-
end
-
-
1
def as_json(*)
-
{ JSON.create_id => self.class.name }.merge to_hash
-
end
-
-
1
def to_json(*a)
-
as_json.to_json(*a)
-
end
-
end
-
end
-
1
module JSON
-
# JSON version
-
1
VERSION = '1.7.5'
-
4
VERSION_ARRAY = VERSION.split(/\./).map { |x| x.to_i } # :nodoc:
-
1
VERSION_MAJOR = VERSION_ARRAY[0] # :nodoc:
-
1
VERSION_MINOR = VERSION_ARRAY[1] # :nodoc:
-
1
VERSION_BUILD = VERSION_ARRAY[2] # :nodoc:
-
end
-
1
module Metaclass
-
end
-
-
1
require "metaclass/version"
-
1
require "metaclass/object_methods"
-
1
module Metaclass::ObjectMethods
-
1
def __metaclass__
-
2034
class << self
-
2034
self
-
end
-
end
-
end
-
-
1
class Object
-
1
include Metaclass::ObjectMethods
-
end
-
1
module Metaclass
-
1
VERSION = "0.0.1"
-
end
-
1
begin
-
1
require 'rubygems'
-
1
gem 'minitest'
-
rescue Gem::LoadError
-
# do nothing
-
end
-
-
1
require 'minitest/unit'
-
1
require 'minitest/spec'
-
1
require 'minitest/mock'
-
-
1
MiniTest::Unit.autorun
-
1
class MockExpectationError < StandardError # :nodoc:
-
end # omg... worst bug ever. rdoc doesn't allow 1-liners
-
-
##
-
# A simple and clean mock object framework.
-
-
1
module MiniTest
-
-
##
-
# All mock objects are an instance of Mock
-
-
1
class Mock
-
1
alias :__respond_to? :respond_to?
-
-
1
skip_methods = %w(object_id respond_to_missing? inspect === to_s)
-
-
1
instance_methods.each do |m|
-
93
undef_method m unless skip_methods.include?(m.to_s) || m =~ /^__/
-
end
-
-
1
def initialize # :nodoc:
-
50
@expected_calls = Hash.new { |calls, name| calls[name] = [] }
-
50
@actual_calls = Hash.new { |calls, name| calls[name] = [] }
-
end
-
-
##
-
# Expect that method +name+ is called, optionally with +args+, and returns
-
# +retval+.
-
#
-
# @mock.expect(:meaning_of_life, 42)
-
# @mock.meaning_of_life # => 42
-
#
-
# @mock.expect(:do_something_with, true, [some_obj, true])
-
# @mock.do_something_with(some_obj, true) # => true
-
#
-
# +args+ is compared to the expected args using case equality (ie, the
-
# '===' operator), allowing for less specific expectations.
-
#
-
# @mock.expect(:uses_any_string, true, [String])
-
# @mock.uses_any_string("foo") # => true
-
# @mock.verify # => true
-
#
-
# @mock.expect(:uses_one_string, true, ["foo"]
-
# @mock.uses_one_string("bar") # => true
-
# @mock.verify # => raises MockExpectationError
-
-
1
def expect(name, retval, args=[])
-
27
raise ArgumentError, "args must be an array" unless Array === args
-
27
@expected_calls[name] << { :retval => retval, :args => args }
-
27
self
-
end
-
-
1
def __call name, data # :nodoc:
-
85
case data
-
when Hash then
-
58
"#{name}(#{data[:args].inspect[1..-2]}) => #{data[:retval].inspect}"
-
else
-
58
data.map { |d| __call name, d }.join ", "
-
end
-
end
-
-
##
-
# Verify that all methods were called as expected. Raises
-
# +MockExpectationError+ if the mock object was not called as
-
# expected.
-
-
1
def verify
-
25
@expected_calls.each do |name, calls|
-
25
calls.each do |expected|
-
27
msg1 = "expected #{__call name, expected}"
-
27
msg2 = "#{msg1}, got [#{__call name, @actual_calls[name]}]"
-
-
raise MockExpectationError, msg2 if
-
@actual_calls.has_key?(name) and
-
27
not @actual_calls[name].include?(expected)
-
-
raise MockExpectationError, msg1 unless
-
@actual_calls.has_key?(name) and
-
27
@actual_calls[name].include?(expected)
-
end
-
end
-
25
true
-
end
-
-
1
def method_missing(sym, *args) # :nodoc:
-
27
unless @expected_calls.has_key?(sym) then
-
raise NoMethodError, "unmocked method %p, expected one of %p" %
-
[sym, @expected_calls.keys.sort_by(&:to_s)]
-
end
-
-
27
index = @actual_calls[sym].length
-
27
expected_call = @expected_calls[sym][index]
-
-
27
unless expected_call then
-
raise MockExpectationError, "No more expects available for %p: %p" %
-
[sym, args]
-
end
-
-
27
expected_args, retval = expected_call[:args], expected_call[:retval]
-
-
27
if expected_args.size != args.size then
-
raise ArgumentError, "mocked method %p expects %d arguments, got %d" %
-
[sym, expected_args.size, args.size]
-
end
-
-
27
fully_matched = expected_args.zip(args).all? { |mod, a|
-
83
mod === a or mod == a
-
}
-
-
27
unless fully_matched then
-
raise MockExpectationError, "mocked method %p called with unexpected arguments %p" %
-
[sym, args]
-
end
-
-
@actual_calls[sym] << {
-
:retval => retval,
-
83
:args => expected_args.zip(args).map { |mod, a| mod === a ? mod : a }
-
27
}
-
-
27
retval
-
end
-
-
1
def respond_to?(sym, include_private = false) # :nodoc:
-
return true if @expected_calls.has_key?(sym.to_sym)
-
return __respond_to?(sym, include_private)
-
end
-
end
-
end
-
-
1
class Object # :nodoc:
-
-
##
-
# Add a temporary stubbed method replacing +name+ for the duration
-
# of the +block+. If +val_or_callable+ responds to #call, then it
-
# returns the result of calling it, otherwise returns the value
-
# as-is. Cleans up the stub at the end of the +block+.
-
#
-
# def test_stale_eh
-
# obj_under_test = Something.new
-
# refute obj_under_test.stale?
-
#
-
# Time.stub :now, Time.at(0) do
-
# assert obj_under_test.stale?
-
# end
-
# end
-
-
1
def stub name, val_or_callable, &block
-
new_name = "__minitest_stub__#{name}"
-
-
metaclass = class << self; self; end
-
-
if respond_to? name and not methods.map(&:to_s).include? name.to_s then
-
metaclass.send :define_method, name do |*args|
-
super(*args)
-
end
-
end
-
-
metaclass.send :alias_method, new_name, name
-
-
metaclass.send :define_method, name do |*args|
-
if val_or_callable.respond_to? :call then
-
val_or_callable.call(*args)
-
else
-
val_or_callable
-
end
-
end
-
-
yield self
-
ensure
-
metaclass.send :undef_method, name
-
metaclass.send :alias_method, name, new_name
-
metaclass.send :undef_method, new_name
-
end
-
end
-
1
class ParallelEach
-
1
require 'thread'
-
1
include Enumerable
-
-
1
N = (ENV['N'] || 2).to_i
-
-
1
def initialize list
-
1
@queue = Queue.new # *sigh*... the Queue api sucks sooo much...
-
-
1
list.each { |i| @queue << i }
-
3
N.times { @queue << nil }
-
end
-
-
1
def grep pattern
-
self.class.new super
-
end
-
-
1
def each
-
1
threads = N.times.map {
-
2
Thread.new do
-
2
Thread.current.abort_on_exception = true
-
2
while job = @queue.pop
-
yield job
-
end
-
end
-
}
-
1
threads.map(&:join)
-
end
-
end
-
#!/usr/bin/ruby -w
-
-
1
require 'minitest/unit'
-
-
1
class Module # :nodoc:
-
1
def infect_an_assertion meth, new_name, dont_flip = false # :nodoc:
-
# warn "%-22p -> %p %p" % [meth, new_name, dont_flip]
-
29
self.class_eval <<-EOM
-
def #{new_name} *args
-
case
-
when Proc === self then
-
MiniTest::Spec.current.#{meth}(*args, &self)
-
when #{!!dont_flip} then
-
MiniTest::Spec.current.#{meth}(self, *args)
-
else
-
MiniTest::Spec.current.#{meth}(args.first, self, *args[1..-1])
-
end
-
end
-
EOM
-
end
-
-
##
-
# infect_with_assertions has been removed due to excessive clever.
-
# Use infect_an_assertion directly instead.
-
-
1
def infect_with_assertions(pos_prefix, neg_prefix,
-
skip_re,
-
dont_flip_re = /\c0/,
-
map = {})
-
abort "infect_with_assertions is dead. Use infect_an_assertion directly"
-
end
-
end
-
-
1
module Kernel # :nodoc:
-
##
-
# Describe a series of expectations for a given target +desc+.
-
#
-
# TODO: find good tutorial url.
-
#
-
# Defines a test class subclassing from either MiniTest::Spec or
-
# from the surrounding describe's class. The surrounding class may
-
# subclass MiniTest::Spec manually in order to easily share code:
-
#
-
# class MySpec < MiniTest::Spec
-
# # ... shared code ...
-
# end
-
#
-
# class TestStuff < MySpec
-
# it "does stuff" do
-
# # shared code available here
-
# end
-
# describe "inner stuff" do
-
# it "still does stuff" do
-
# # ...and here
-
# end
-
# end
-
# end
-
-
1
def describe desc, additional_desc = nil, &block # :doc:
-
stack = MiniTest::Spec.describe_stack
-
name = [stack.last, desc, additional_desc].compact.join("::")
-
sclas = stack.last || if Class === self && self < MiniTest::Spec then
-
self
-
else
-
MiniTest::Spec.spec_type desc
-
end
-
-
cls = sclas.create name, desc
-
-
stack.push cls
-
cls.class_eval(&block)
-
stack.pop
-
cls
-
end
-
1
private :describe
-
end
-
-
##
-
# MiniTest::Spec -- The faster, better, less-magical spec framework!
-
#
-
# For a list of expectations, see MiniTest::Expectations.
-
-
1
class MiniTest::Spec < MiniTest::Unit::TestCase
-
##
-
# Contains pairs of matchers and Spec classes to be used to
-
# calculate the superclass of a top-level describe. This allows for
-
# automatically customizable spec types.
-
#
-
# See: register_spec_type and spec_type
-
-
1
TYPES = [[//, MiniTest::Spec]]
-
-
##
-
# Register a new type of spec that matches the spec's description.
-
# This method can take either a Regexp and a spec class or a spec
-
# class and a block that takes the description and returns true if
-
# it matches.
-
#
-
# Eg:
-
#
-
# register_spec_type(/Controller$/, MiniTest::Spec::Rails)
-
#
-
# or:
-
#
-
# register_spec_type(MiniTest::Spec::RailsModel) do |desc|
-
# desc.superclass == ActiveRecord::Base
-
# end
-
-
1
def self.register_spec_type(*args, &block)
-
1
if block then
-
1
matcher, klass = block, args.first
-
else
-
matcher, klass = *args
-
end
-
1
TYPES.unshift [matcher, klass]
-
end
-
-
##
-
# Figure out the spec class to use based on a spec's description. Eg:
-
#
-
# spec_type("BlahController") # => MiniTest::Spec::Rails
-
-
1
def self.spec_type desc
-
TYPES.find { |matcher, klass|
-
if matcher.respond_to? :call then
-
matcher.call desc
-
else
-
matcher === desc.to_s
-
end
-
}.last
-
end
-
-
1
@@describe_stack = []
-
1
def self.describe_stack # :nodoc:
-
@@describe_stack
-
end
-
-
##
-
# Returns the children of this spec.
-
-
1
def self.children
-
170
@children ||= []
-
end
-
-
1
def self.nuke_test_methods! # :nodoc:
-
self.public_instance_methods.grep(/^test_/).each do |name|
-
self.send :undef_method, name
-
end
-
end
-
-
##
-
# Define a 'before' action. Inherits the way normal methods should.
-
#
-
# NOTE: +type+ is ignored and is only there to make porting easier.
-
#
-
# Equivalent to MiniTest::Unit::TestCase#setup.
-
-
1
def self.before type = nil, &block
-
define_method :setup do
-
super()
-
self.instance_eval(&block)
-
end
-
end
-
-
##
-
# Define an 'after' action. Inherits the way normal methods should.
-
#
-
# NOTE: +type+ is ignored and is only there to make porting easier.
-
#
-
# Equivalent to MiniTest::Unit::TestCase#teardown.
-
-
1
def self.after type = nil, &block
-
define_method :teardown do
-
self.instance_eval(&block)
-
super()
-
end
-
end
-
-
##
-
# Define an expectation with name +desc+. Name gets morphed to a
-
# proper test method name. For some freakish reason, people who
-
# write specs don't like class inheritence, so this goes way out of
-
# its way to make sure that expectations aren't inherited.
-
#
-
# This is also aliased to #specify and doesn't require a +desc+ arg.
-
#
-
# Hint: If you _do_ want inheritence, use minitest/unit. You can mix
-
# and match between assertions and expectations as much as you want.
-
-
1
def self.it desc = "anonymous", &block
-
170
block ||= proc { skip "(no tests defined)" }
-
-
170
@specs ||= 0
-
170
@specs += 1
-
-
170
name = "test_%04d_%s" % [ @specs, desc ]
-
-
170
define_method name, &block
-
-
170
self.children.each do |mod|
-
mod.send :undef_method, name if mod.public_method_defined? name
-
end
-
-
170
name
-
end
-
-
##
-
# Essentially, define an accessor for +name+ with +block+.
-
#
-
# Why use let instead of def? I honestly don't know.
-
-
1
def self.let name, &block
-
define_method name do
-
@_memoized ||= {}
-
@_memoized.fetch(name) { |k| @_memoized[k] = instance_eval(&block) }
-
end
-
end
-
-
##
-
# Another lazy man's accessor generator. Made even more lazy by
-
# setting the name for you to +subject+.
-
-
1
def self.subject &block
-
let :subject, &block
-
end
-
-
1
def self.create name, desc # :nodoc:
-
cls = Class.new(self) do
-
@name = name
-
@desc = desc
-
-
nuke_test_methods!
-
end
-
-
children << cls
-
-
cls
-
end
-
-
1
def self.to_s # :nodoc:
-
7586
defined?(@name) ? @name : super
-
end
-
-
# :stopdoc:
-
1
class << self
-
1
attr_reader :desc
-
1
alias :specify :it
-
1
alias :name :to_s
-
end
-
# :startdoc:
-
end
-
-
##
-
# It's where you hide your "assertions".
-
-
1
module MiniTest::Expectations
-
##
-
# See MiniTest::Assertions#assert_empty.
-
#
-
# collection.must_be_empty
-
#
-
# :method: must_be_empty
-
-
1
infect_an_assertion :assert_empty, :must_be_empty, :unary
-
-
##
-
# See MiniTest::Assertions#assert_equal
-
#
-
# a.must_equal b
-
#
-
# :method: must_equal
-
-
1
infect_an_assertion :assert_equal, :must_equal
-
-
##
-
# See MiniTest::Assertions#assert_in_delta
-
#
-
# n.must_be_close_to m [, delta]
-
#
-
# :method: must_be_close_to
-
-
1
infect_an_assertion :assert_in_delta, :must_be_close_to
-
-
1
alias :must_be_within_delta :must_be_close_to # :nodoc:
-
-
##
-
# See MiniTest::Assertions#assert_in_epsilon
-
#
-
# n.must_be_within_epsilon m [, epsilon]
-
#
-
# :method: must_be_within_epsilon
-
-
1
infect_an_assertion :assert_in_epsilon, :must_be_within_epsilon
-
-
##
-
# See MiniTest::Assertions#assert_includes
-
#
-
# collection.must_include obj
-
#
-
# :method: must_include
-
-
1
infect_an_assertion :assert_includes, :must_include, :reverse
-
-
##
-
# See MiniTest::Assertions#assert_instance_of
-
#
-
# obj.must_be_instance_of klass
-
#
-
# :method: must_be_instance_of
-
-
1
infect_an_assertion :assert_instance_of, :must_be_instance_of
-
-
##
-
# See MiniTest::Assertions#assert_kind_of
-
#
-
# obj.must_be_kind_of mod
-
#
-
# :method: must_be_kind_of
-
-
1
infect_an_assertion :assert_kind_of, :must_be_kind_of
-
-
##
-
# See MiniTest::Assertions#assert_match
-
#
-
# a.must_match b
-
#
-
# :method: must_match
-
-
1
infect_an_assertion :assert_match, :must_match
-
-
##
-
# See MiniTest::Assertions#assert_nil
-
#
-
# obj.must_be_nil
-
#
-
# :method: must_be_nil
-
-
1
infect_an_assertion :assert_nil, :must_be_nil, :unary
-
-
##
-
# See MiniTest::Assertions#assert_operator
-
#
-
# n.must_be :<=, 42
-
#
-
# This can also do predicates:
-
#
-
# str.must_be :empty?
-
#
-
# :method: must_be
-
-
1
infect_an_assertion :assert_operator, :must_be, :reverse
-
-
##
-
# See MiniTest::Assertions#assert_output
-
#
-
# proc { ... }.must_output out_or_nil [, err]
-
#
-
# :method: must_output
-
-
1
infect_an_assertion :assert_output, :must_output
-
-
##
-
# See MiniTest::Assertions#assert_raises
-
#
-
# proc { ... }.must_raise exception
-
#
-
# :method: must_raise
-
-
1
infect_an_assertion :assert_raises, :must_raise
-
-
##
-
# See MiniTest::Assertions#assert_respond_to
-
#
-
# obj.must_respond_to msg
-
#
-
# :method: must_respond_to
-
-
1
infect_an_assertion :assert_respond_to, :must_respond_to, :reverse
-
-
##
-
# See MiniTest::Assertions#assert_same
-
#
-
# a.must_be_same_as b
-
#
-
# :method: must_be_same_as
-
-
1
infect_an_assertion :assert_same, :must_be_same_as
-
-
##
-
# See MiniTest::Assertions#assert_send
-
# TODO: remove me
-
#
-
# a.must_send
-
#
-
# :method: must_send
-
-
1
infect_an_assertion :assert_send, :must_send
-
-
##
-
# See MiniTest::Assertions#assert_silent
-
#
-
# proc { ... }.must_be_silent
-
#
-
# :method: must_be_silent
-
-
1
infect_an_assertion :assert_silent, :must_be_silent
-
-
##
-
# See MiniTest::Assertions#assert_throws
-
#
-
# proc { ... }.must_throw sym
-
#
-
# :method: must_throw
-
-
1
infect_an_assertion :assert_throws, :must_throw
-
-
##
-
# See MiniTest::Assertions#refute_empty
-
#
-
# collection.wont_be_empty
-
#
-
# :method: wont_be_empty
-
-
1
infect_an_assertion :refute_empty, :wont_be_empty, :unary
-
-
##
-
# See MiniTest::Assertions#refute_equal
-
#
-
# a.wont_equal b
-
#
-
# :method: wont_equal
-
-
1
infect_an_assertion :refute_equal, :wont_equal
-
-
##
-
# See MiniTest::Assertions#refute_in_delta
-
#
-
# n.wont_be_close_to m [, delta]
-
#
-
# :method: wont_be_close_to
-
-
1
infect_an_assertion :refute_in_delta, :wont_be_close_to
-
-
1
alias :wont_be_within_delta :wont_be_close_to # :nodoc:
-
-
##
-
# See MiniTest::Assertions#refute_in_epsilon
-
#
-
# n.wont_be_within_epsilon m [, epsilon]
-
#
-
# :method: wont_be_within_epsilon
-
-
1
infect_an_assertion :refute_in_epsilon, :wont_be_within_epsilon
-
-
##
-
# See MiniTest::Assertions#refute_includes
-
#
-
# collection.wont_include obj
-
#
-
# :method: wont_include
-
-
1
infect_an_assertion :refute_includes, :wont_include, :reverse
-
-
##
-
# See MiniTest::Assertions#refute_instance_of
-
#
-
# obj.wont_be_instance_of klass
-
#
-
# :method: wont_be_instance_of
-
-
1
infect_an_assertion :refute_instance_of, :wont_be_instance_of
-
-
##
-
# See MiniTest::Assertions#refute_kind_of
-
#
-
# obj.wont_be_kind_of mod
-
#
-
# :method: wont_be_kind_of
-
-
1
infect_an_assertion :refute_kind_of, :wont_be_kind_of
-
-
##
-
# See MiniTest::Assertions#refute_match
-
#
-
# a.wont_match b
-
#
-
# :method: wont_match
-
-
1
infect_an_assertion :refute_match, :wont_match
-
-
##
-
# See MiniTest::Assertions#refute_nil
-
#
-
# obj.wont_be_nil
-
#
-
# :method: wont_be_nil
-
-
1
infect_an_assertion :refute_nil, :wont_be_nil, :unary
-
-
##
-
# See MiniTest::Assertions#refute_operator
-
#
-
# n.wont_be :<=, 42
-
#
-
# This can also do predicates:
-
#
-
# str.wont_be :empty?
-
#
-
# :method: wont_be
-
-
1
infect_an_assertion :refute_operator, :wont_be, :reverse
-
-
##
-
# See MiniTest::Assertions#refute_respond_to
-
#
-
# obj.wont_respond_to msg
-
#
-
# :method: wont_respond_to
-
-
1
infect_an_assertion :refute_respond_to, :wont_respond_to, :reverse
-
-
##
-
# See MiniTest::Assertions#refute_same
-
#
-
# a.wont_be_same_as b
-
#
-
# :method: wont_be_same_as
-
-
1
infect_an_assertion :refute_same, :wont_be_same_as
-
end
-
-
1
class Object # :nodoc:
-
1
include MiniTest::Expectations
-
end
-
1
require 'optparse'
-
1
require 'rbconfig'
-
1
require 'thread' # required for 1.8
-
1
require 'minitest/parallel_each'
-
-
##
-
# Minimal (mostly drop-in) replacement for test-unit.
-
#
-
# :include: README.txt
-
-
1
module MiniTest
-
-
1
def self.const_missing name # :nodoc:
-
case name
-
when :MINI_DIR then
-
msg = "MiniTest::MINI_DIR was removed. Don't violate other's internals."
-
warn "WAR\NING: #{msg}"
-
warn "WAR\NING: Used by #{caller.first}."
-
const_set :MINI_DIR, "bad value"
-
else
-
super
-
end
-
end
-
-
##
-
# Assertion base class
-
-
1
class Assertion < Exception; end
-
-
##
-
# Assertion raised when skipping a test
-
-
1
class Skip < Assertion; end
-
-
1
class << self
-
1
attr_accessor :backtrace_filter
-
end
-
-
1
class BacktraceFilter # :nodoc:
-
1
def filter bt
-
363
return ["No backtrace"] unless bt
-
-
363
new_bt = []
-
-
363
unless $DEBUG then
-
363
bt.each do |line|
-
3945
break if line =~ /lib\/minitest/
-
3582
new_bt << line
-
end
-
-
363
new_bt = bt.reject { |line| line =~ /lib\/minitest/ } if new_bt.empty?
-
363
new_bt = bt.dup if new_bt.empty?
-
else
-
new_bt = bt.dup
-
end
-
-
363
new_bt
-
end
-
end
-
-
1
self.backtrace_filter = BacktraceFilter.new
-
-
1
def self.filter_backtrace bt # :nodoc:
-
363
backtrace_filter.filter bt
-
end
-
-
##
-
# MiniTest Assertions. All assertion methods accept a +msg+ which is
-
# printed if the assertion fails.
-
-
1
module Assertions
-
1
UNDEFINED = Object.new # :nodoc:
-
-
1
def UNDEFINED.inspect # :nodoc:
-
"UNDEFINED" # again with the rdoc bugs... :(
-
end
-
-
##
-
# Returns the diff command to use in #diff. Tries to intelligently
-
# figure out what diff to use.
-
-
1
def self.diff
-
@diff = if RbConfig::CONFIG['host_os'] =~ /mswin|mingw/ then
-
"diff.exe -u"
-
else
-
if system("gdiff", __FILE__, __FILE__)
-
"gdiff -u" # solaris and kin suck
-
elsif system("diff", __FILE__, __FILE__)
-
"diff -u"
-
else
-
nil
-
end
-
end unless defined? @diff
-
-
@diff
-
end
-
-
##
-
# Set the diff command to use in #diff.
-
-
1
def self.diff= o
-
@diff = o
-
end
-
-
##
-
# Returns a diff between +exp+ and +act+. If there is no known
-
# diff command or if it doesn't make sense to diff the output
-
# (single line, short output), then it simply returns a basic
-
# comparison between the two.
-
-
1
def diff exp, act
-
require "tempfile"
-
-
expect = mu_pp_for_diff exp
-
butwas = mu_pp_for_diff act
-
result = nil
-
-
need_to_diff =
-
MiniTest::Assertions.diff &&
-
(expect.include?("\n") ||
-
butwas.include?("\n") ||
-
expect.size > 30 ||
-
butwas.size > 30 ||
-
expect == butwas)
-
-
return "Expected: #{mu_pp exp}\n Actual: #{mu_pp act}" unless
-
need_to_diff
-
-
Tempfile.open("expect") do |a|
-
a.puts expect
-
a.flush
-
-
Tempfile.open("butwas") do |b|
-
b.puts butwas
-
b.flush
-
-
result = `#{MiniTest::Assertions.diff} #{a.path} #{b.path}`
-
result.sub!(/^\-\-\- .+/, "--- expected")
-
result.sub!(/^\+\+\+ .+/, "+++ actual")
-
-
if result.empty? then
-
klass = exp.class
-
result = [
-
"No visible difference in the #{klass}#inspect output.",
-
"You should look at your implementation of #{klass}#==.",
-
expect
-
].join "\n"
-
end
-
end
-
end
-
-
result
-
end
-
-
##
-
# This returns a human-readable version of +obj+. By default
-
# #inspect is called. You can override this to use #pretty_print
-
# if you want.
-
-
1
def mu_pp obj
-
363
s = obj.inspect
-
363
s = s.encode Encoding.default_external if defined? Encoding
-
363
s
-
end
-
-
##
-
# This returns a diff-able human-readable version of +obj+. This
-
# differs from the regular mu_pp because it expands escaped
-
# newlines and makes hex-values generic (like object_ids). This
-
# uses mu_pp to do the first pass and then cleans it up.
-
-
1
def mu_pp_for_diff obj # TODO: possibly rename
-
mu_pp(obj).gsub(/\\n/, "\n").gsub(/0x[a-f0-9]+/m, '0xXXXXXX')
-
end
-
-
1
def _assertions= n # :nodoc:
-
13983
@_assertions = n
-
end
-
-
1
def _assertions # :nodoc:
-
17623
@_assertions ||= 0
-
end
-
-
##
-
# Fails unless +test+ is a true value.
-
-
1
def assert test, msg = nil
-
10343
msg ||= "Failed assertion, no message given."
-
10343
self._assertions += 1
-
10343
unless test then
-
msg = msg.call if Proc === msg
-
raise MiniTest::Assertion, msg
-
end
-
10343
true
-
end
-
-
##
-
# Fails unless the block returns a true value.
-
#
-
# NOTE: This method is deprecated, use assert. It will be removed
-
# on 2013-01-01."
-
-
1
def assert_block msg = nil
-
warn "NOTE: MiniTest::Unit::TestCase#assert_block is deprecated, use assert. It will be removed on 2013-01-01. Called from #{caller.first}"
-
msg = message(msg) { "Expected block to return true value" }
-
assert yield, msg
-
end
-
-
##
-
# Fails unless +obj+ is empty.
-
-
1
def assert_empty obj, msg = nil
-
2
msg = message(msg) { "Expected #{mu_pp(obj)} to be empty" }
-
2
assert_respond_to obj, :empty?
-
2
assert obj.empty?, msg
-
end
-
-
##
-
# Fails unless <tt>exp == act</tt> printing the difference between
-
# the two, if possible.
-
#
-
# If there is no visible difference but the assertion fails, you
-
# should suspect that your #== is buggy, or your inspect output is
-
# missing crucial details.
-
#
-
# For floats use assert_in_delta.
-
#
-
# See also: MiniTest::Assertions.diff
-
-
1
def assert_equal exp, act, msg = nil
-
5404
msg = message(msg, "") { diff exp, act }
-
5404
assert(exp == act, msg)
-
end
-
-
##
-
# For comparing Floats. Fails unless +exp+ and +act+ are within +delta+
-
# of each other.
-
#
-
# assert_in_delta Math::PI, (22.0 / 7.0), 0.01
-
-
1
def assert_in_delta exp, act, delta = 0.001, msg = nil
-
1
n = (exp - act).abs
-
1
msg = message(msg) { "Expected |#{exp} - #{act}| (#{n}) to be < #{delta}"}
-
1
assert delta >= n, msg
-
end
-
-
##
-
# For comparing Floats. Fails unless +exp+ and +act+ have a relative
-
# error less than +epsilon+.
-
-
1
def assert_in_epsilon a, b, epsilon = 0.001, msg = nil
-
assert_in_delta a, b, [a.abs, b.abs].min * epsilon, msg
-
end
-
-
##
-
# Fails unless +collection+ includes +obj+.
-
-
1
def assert_includes collection, obj, msg = nil
-
msg = message(msg) {
-
"Expected #{mu_pp(collection)} to include #{mu_pp(obj)}"
-
}
-
assert_respond_to collection, :include?
-
assert collection.include?(obj), msg
-
end
-
-
##
-
# Fails unless +obj+ is an instance of +cls+.
-
-
1
def assert_instance_of cls, obj, msg = nil
-
15
msg = message(msg) {
-
"Expected #{mu_pp(obj)} to be an instance of #{cls}, not #{obj.class}"
-
}
-
-
15
assert obj.instance_of?(cls), msg
-
end
-
-
##
-
# Fails unless +obj+ is a kind of +cls+.
-
-
1
def assert_kind_of cls, obj, msg = nil # TODO: merge with instance_of
-
269
msg = message(msg) {
-
"Expected #{mu_pp(obj)} to be a kind of #{cls}, not #{obj.class}" }
-
-
269
assert obj.kind_of?(cls), msg
-
end
-
-
##
-
# Fails unless +matcher+ <tt>=~</tt> +obj+.
-
-
1
def assert_match matcher, obj, msg = nil
-
382
msg = message(msg) { "Expected #{mu_pp matcher} to match #{mu_pp obj}" }
-
382
assert_respond_to matcher, :"=~"
-
382
matcher = Regexp.new Regexp.escape matcher if String === matcher
-
382
assert matcher =~ obj, msg
-
end
-
-
##
-
# Fails unless +obj+ is nil
-
-
1
def assert_nil obj, msg = nil
-
265
msg = message(msg) { "Expected #{mu_pp(obj)} to be nil" }
-
265
assert obj.nil?, msg
-
end
-
-
##
-
# For testing with binary operators.
-
#
-
# assert_operator 5, :<=, 4
-
-
1
def assert_operator o1, op, o2 = UNDEFINED, msg = nil
-
4
return assert_predicate o1, op, msg if UNDEFINED == o2
-
4
msg = message(msg) { "Expected #{mu_pp(o1)} to be #{op} #{mu_pp(o2)}" }
-
4
assert o1.__send__(op, o2), msg
-
end
-
-
##
-
# Fails if stdout or stderr do not output the expected results.
-
# Pass in nil if you don't care about that streams output. Pass in
-
# "" if you require it to be silent. Pass in a regexp if you want
-
# to pattern match.
-
#
-
# NOTE: this uses #capture_io, not #capture_subprocess_io.
-
#
-
# See also: #assert_silent
-
-
1
def assert_output stdout = nil, stderr = nil
-
out, err = capture_io do
-
yield
-
end
-
-
err_msg = Regexp === stderr ? :assert_match : :assert_equal if stderr
-
out_msg = Regexp === stdout ? :assert_match : :assert_equal if stdout
-
-
y = send err_msg, stderr, err, "In stderr" if err_msg
-
x = send out_msg, stdout, out, "In stdout" if out_msg
-
-
(!stdout || x) && (!stderr || y)
-
end
-
-
##
-
# For testing with predicates.
-
#
-
# assert_predicate str, :empty?
-
#
-
# This is really meant for specs and is front-ended by assert_operator:
-
#
-
# str.must_be :empty?
-
-
1
def assert_predicate o1, op, msg = nil
-
msg = message(msg) { "Expected #{mu_pp(o1)} to be #{op}" }
-
assert o1.__send__(op), msg
-
end
-
-
##
-
# Fails unless the block raises one of +exp+. Returns the
-
# exception matched so you can check the message, attributes, etc.
-
-
1
def assert_raises *exp
-
363
msg = "#{exp.pop}.\n" if String === exp.last
-
-
363
should_raise = false
-
363
begin
-
363
yield
-
should_raise = true
-
rescue MiniTest::Skip => e
-
details = "#{msg}#{mu_pp(exp)} exception expected, not"
-
-
if exp.include? MiniTest::Skip then
-
return e
-
else
-
raise e
-
end
-
rescue Exception => e
-
363
details = "#{msg}#{mu_pp(exp)} exception expected, not"
-
assert(exp.any? { |ex|
-
363
ex.instance_of?(Module) ? e.kind_of?(ex) : ex == e.class
-
363
}, exception_details(e, details))
-
-
363
return e
-
end
-
-
exp = exp.first if exp.size == 1
-
flunk "#{msg}#{mu_pp(exp)} expected but nothing was raised." if
-
should_raise
-
end
-
-
##
-
# Fails unless +obj+ responds to +meth+.
-
-
1
def assert_respond_to obj, meth, msg = nil
-
487
msg = message(msg) {
-
"Expected #{mu_pp(obj)} (#{obj.class}) to respond to ##{meth}"
-
}
-
487
assert obj.respond_to?(meth), msg
-
end
-
-
##
-
# Fails unless +exp+ and +act+ are #equal?
-
-
1
def assert_same exp, act, msg = nil
-
2
msg = message(msg) {
-
data = [mu_pp(act), act.object_id, mu_pp(exp), exp.object_id]
-
"Expected %s (oid=%d) to be the same as %s (oid=%d)" % data
-
}
-
2
assert exp.equal?(act), msg
-
end
-
-
##
-
# +send_ary+ is a receiver, message and arguments.
-
#
-
# Fails unless the call returns a true value
-
# TODO: I should prolly remove this from specs
-
-
1
def assert_send send_ary, m = nil
-
recv, msg, *args = send_ary
-
m = message(m) {
-
"Expected #{mu_pp(recv)}.#{msg}(*#{mu_pp(args)}) to return true" }
-
assert recv.__send__(msg, *args), m
-
end
-
-
##
-
# Fails if the block outputs anything to stderr or stdout.
-
#
-
# See also: #assert_output
-
-
1
def assert_silent
-
assert_output "", "" do
-
yield
-
end
-
end
-
-
##
-
# Fails unless the block throws +sym+
-
-
1
def assert_throws sym, msg = nil
-
default = "Expected #{mu_pp(sym)} to have been thrown"
-
caught = true
-
catch(sym) do
-
begin
-
yield
-
rescue ThreadError => e # wtf?!? 1.8 + threads == suck
-
default += ", not :#{e.message[/uncaught throw \`(\w+?)\'/, 1]}"
-
rescue ArgumentError => e # 1.9 exception
-
default += ", not #{e.message.split(/ /).last}"
-
rescue NameError => e # 1.8 exception
-
default += ", not #{e.name.inspect}"
-
end
-
caught = false
-
end
-
-
assert caught, message(msg) { default }
-
end
-
-
##
-
# Captures $stdout and $stderr into strings:
-
#
-
# out, err = capture_io do
-
# puts "Some info"
-
# warn "You did a bad thing"
-
# end
-
#
-
# assert_match %r%info%, out
-
# assert_match %r%bad%, err
-
#
-
# NOTE: For efficiency, this method uses StringIO and does not
-
# capture IO for subprocesses. Use #capture_subprocess_io for
-
# that.
-
-
1
def capture_io
-
require 'stringio'
-
-
captured_stdout, captured_stderr = StringIO.new, StringIO.new
-
-
synchronize do
-
orig_stdout, orig_stderr = $stdout, $stderr
-
$stdout, $stderr = captured_stdout, captured_stderr
-
-
begin
-
yield
-
ensure
-
$stdout = orig_stdout
-
$stderr = orig_stderr
-
end
-
end
-
-
return captured_stdout.string, captured_stderr.string
-
end
-
-
##
-
# Captures $stdout and $stderr into strings, using Tempfile to
-
# ensure that subprocess IO is captured as well.
-
#
-
# out, err = capture_subprocess_io do
-
# system "echo Some info"
-
# system "echo You did a bad thing 1>&2"
-
# end
-
#
-
# assert_match %r%info%, out
-
# assert_match %r%bad%, err
-
#
-
# NOTE: This method is approximately 10x slower than #capture_io so
-
# only use it when you need to test the output of a subprocess.
-
-
1
def capture_subprocess_io
-
require 'tempfile'
-
-
captured_stdout, captured_stderr = Tempfile.new("out"), Tempfile.new("err")
-
-
synchronize do
-
orig_stdout, orig_stderr = $stdout.dup, $stderr.dup
-
$stdout.reopen captured_stdout
-
$stderr.reopen captured_stderr
-
-
begin
-
yield
-
-
$stdout.rewind
-
$stderr.rewind
-
-
[captured_stdout.read, captured_stderr.read]
-
ensure
-
captured_stdout.unlink
-
captured_stderr.unlink
-
$stdout.reopen orig_stdout
-
$stderr.reopen orig_stderr
-
end
-
end
-
end
-
-
##
-
# Returns details for exception +e+
-
-
1
def exception_details e, msg
-
[
-
363
"#{msg}",
-
"Class: <#{e.class}>",
-
"Message: <#{e.message.inspect}>",
-
"---Backtrace---",
-
"#{MiniTest::filter_backtrace(e.backtrace).join("\n")}",
-
"---------------",
-
].join "\n"
-
end
-
-
##
-
# Fails with +msg+
-
-
1
def flunk msg = nil
-
msg ||= "Epic Fail!"
-
assert false, msg
-
end
-
-
##
-
# Returns a proc that will output +msg+ along with the default message.
-
-
1
def message msg = nil, ending = ".", &default
-
7294
proc {
-
custom_message = "#{msg}.\n" unless msg.nil? or msg.to_s.empty?
-
"#{custom_message}#{default.call}#{ending}"
-
}
-
end
-
-
##
-
# used for counting assertions
-
-
1
def pass msg = nil
-
assert true
-
end
-
-
##
-
# Fails if +test+ is a true value
-
-
1
def refute test, msg = nil
-
504
msg ||= "Failed refutation, no message given"
-
504
not assert(! test, msg)
-
end
-
-
##
-
# Fails if +obj+ is empty.
-
-
1
def refute_empty obj, msg = nil
-
msg = message(msg) { "Expected #{mu_pp(obj)} to not be empty" }
-
assert_respond_to obj, :empty?
-
refute obj.empty?, msg
-
end
-
-
##
-
# Fails if <tt>exp == act</tt>.
-
#
-
# For floats use refute_in_delta.
-
-
1
def refute_equal exp, act, msg = nil
-
77
msg = message(msg) {
-
"Expected #{mu_pp(act)} to not be equal to #{mu_pp(exp)}"
-
}
-
77
refute exp == act, msg
-
end
-
-
##
-
# For comparing Floats. Fails if +exp+ is within +delta+ of +act+.
-
#
-
# refute_in_delta Math::PI, (22.0 / 7.0)
-
-
1
def refute_in_delta exp, act, delta = 0.001, msg = nil
-
n = (exp - act).abs
-
msg = message(msg) {
-
"Expected |#{exp} - #{act}| (#{n}) to not be < #{delta}"
-
}
-
refute delta > n, msg
-
end
-
-
##
-
# For comparing Floats. Fails if +exp+ and +act+ have a relative error
-
# less than +epsilon+.
-
-
1
def refute_in_epsilon a, b, epsilon = 0.001, msg = nil
-
refute_in_delta a, b, a * epsilon, msg
-
end
-
-
##
-
# Fails if +collection+ includes +obj+.
-
-
1
def refute_includes collection, obj, msg = nil
-
msg = message(msg) {
-
"Expected #{mu_pp(collection)} to not include #{mu_pp(obj)}"
-
}
-
assert_respond_to collection, :include?
-
refute collection.include?(obj), msg
-
end
-
-
##
-
# Fails if +obj+ is an instance of +cls+.
-
-
1
def refute_instance_of cls, obj, msg = nil
-
msg = message(msg) {
-
"Expected #{mu_pp(obj)} to not be an instance of #{cls}"
-
}
-
refute obj.instance_of?(cls), msg
-
end
-
-
##
-
# Fails if +obj+ is a kind of +cls+.
-
-
1
def refute_kind_of cls, obj, msg = nil # TODO: merge with instance_of
-
msg = message(msg) { "Expected #{mu_pp(obj)} to not be a kind of #{cls}" }
-
refute obj.kind_of?(cls), msg
-
end
-
-
##
-
# Fails if +matcher+ <tt>=~</tt> +obj+.
-
-
1
def refute_match matcher, obj, msg = nil
-
49
msg = message(msg) {"Expected #{mu_pp matcher} to not match #{mu_pp obj}"}
-
49
assert_respond_to matcher, :"=~"
-
49
matcher = Regexp.new Regexp.escape matcher if String === matcher
-
49
refute matcher =~ obj, msg
-
end
-
-
##
-
# Fails if +obj+ is nil.
-
-
1
def refute_nil obj, msg = nil
-
337
msg = message(msg) { "Expected #{mu_pp(obj)} to not be nil" }
-
337
refute obj.nil?, msg
-
end
-
-
##
-
# Fails if +o1+ is not +op+ +o2+. Eg:
-
#
-
# refute_operator 1, :>, 2 #=> pass
-
# refute_operator 1, :<, 2 #=> fail
-
-
1
def refute_operator o1, op, o2 = UNDEFINED, msg = nil
-
return refute_predicate o1, op, msg if UNDEFINED == o2
-
msg = message(msg) { "Expected #{mu_pp(o1)} to not be #{op} #{mu_pp(o2)}"}
-
refute o1.__send__(op, o2), msg
-
end
-
-
##
-
# For testing with predicates.
-
#
-
# refute_predicate str, :empty?
-
#
-
# This is really meant for specs and is front-ended by refute_operator:
-
#
-
# str.wont_be :empty?
-
-
1
def refute_predicate o1, op, msg = nil
-
msg = message(msg) { "Expected #{mu_pp(o1)} to not be #{op}" }
-
refute o1.__send__(op), msg
-
end
-
-
##
-
# Fails if +obj+ responds to the message +meth+.
-
-
1
def refute_respond_to obj, meth, msg = nil
-
msg = message(msg) { "Expected #{mu_pp(obj)} to not respond to #{meth}" }
-
-
refute obj.respond_to?(meth), msg
-
end
-
-
##
-
# Fails if +exp+ is the same (by object identity) as +act+.
-
-
1
def refute_same exp, act, msg = nil
-
msg = message(msg) {
-
data = [mu_pp(act), act.object_id, mu_pp(exp), exp.object_id]
-
"Expected %s (oid=%d) to not be the same as %s (oid=%d)" % data
-
}
-
refute exp.equal?(act), msg
-
end
-
-
##
-
# Skips the current test. Gets listed at the end of the run but
-
# doesn't cause a failure exit code.
-
-
1
def skip msg = nil, bt = caller
-
51
msg ||= "Skipped, no message given"
-
51
raise MiniTest::Skip, msg, bt
-
end
-
-
##
-
# Takes a block and wraps it with the runner's shared mutex.
-
-
1
def synchronize
-
Minitest::Unit.runner.synchronize do
-
yield
-
end
-
end
-
end
-
-
1
class Unit # :nodoc:
-
1
VERSION = "4.2.0" # :nodoc:
-
-
1
attr_accessor :report, :failures, :errors, :skips # :nodoc:
-
1
attr_accessor :test_count, :assertion_count # :nodoc:
-
1
attr_accessor :start_time # :nodoc:
-
1
attr_accessor :help # :nodoc:
-
1
attr_accessor :verbose # :nodoc:
-
1
attr_writer :options # :nodoc:
-
-
##
-
# Lazy accessor for options.
-
-
1
def options
-
264
@options ||= {}
-
end
-
-
1
@@installed_at_exit ||= false
-
1
@@out = $stdout
-
1
@@after_tests = []
-
-
##
-
# A simple hook allowing you to run a block of code after _all_ of
-
# the tests are done. Eg:
-
#
-
# MiniTest::Unit.after_tests { p $debugging_info }
-
-
1
def self.after_tests &block
-
@@after_tests << block
-
end
-
-
##
-
# Registers MiniTest::Unit to run tests at process exit
-
-
1
def self.autorun
-
at_exit {
-
1
next if $! # don't run if there was an exception
-
-
# the order here is important. The at_exit handler must be
-
# installed before anyone else gets a chance to install their
-
# own, that way we can be assured that our exit will be last
-
# to run (at_exit stacks).
-
1
exit_code = nil
-
-
1
at_exit {
-
1
@@after_tests.reverse_each(&:call)
-
1
exit false if exit_code && exit_code != 0
-
}
-
-
1
exit_code = MiniTest::Unit.new.run ARGV
-
1
} unless @@installed_at_exit
-
1
@@installed_at_exit = true
-
end
-
-
##
-
# Returns the stream to use for output.
-
-
1
def self.output
-
3653
@@out
-
end
-
-
##
-
# Sets MiniTest::Unit to write output to +stream+. $stdout is the default
-
# output
-
-
1
def self.output= stream
-
@@out = stream
-
end
-
-
##
-
# Tells MiniTest::Unit to delegate to +runner+, an instance of a
-
# MiniTest::Unit subclass, when MiniTest::Unit#run is called.
-
-
1
def self.runner= runner
-
@@runner = runner
-
end
-
-
##
-
# Returns the MiniTest::Unit subclass instance that will be used
-
# to run the tests. A MiniTest::Unit instance is the default
-
# runner.
-
-
1
def self.runner
-
1
@@runner ||= self.new
-
end
-
-
##
-
# Return all plugins' run methods (methods that start with "run_").
-
-
1
def self.plugins
-
@@plugins ||= (["run_tests"] +
-
public_instance_methods(false).
-
2
grep(/^run_/).map { |s| s.to_s }).uniq
-
end
-
-
##
-
# Return the IO for output.
-
-
1
def output
-
3653
self.class.output
-
end
-
-
1
def puts *a # :nodoc:
-
8
output.puts(*a)
-
end
-
-
1
def print *a # :nodoc:
-
3640
output.print(*a)
-
end
-
-
##
-
# Runner for a given +type+ (eg, test vs bench).
-
-
1
def _run_anything type
-
1
suites = TestCase.send "#{type}_suites"
-
1
return if suites.empty?
-
-
1
start = Time.now
-
-
1
puts
-
1
puts "# Running #{type}s:"
-
1
puts
-
-
1
@test_count, @assertion_count = 0, 0
-
1
sync = output.respond_to? :"sync=" # stupid emacs
-
1
old_sync, output.sync = output.sync, true if sync
-
-
1
results = _run_suites suites, type
-
-
265
@test_count = results.inject(0) { |sum, (tc, _)| sum + tc }
-
265
@assertion_count = results.inject(0) { |sum, (_, ac)| sum + ac }
-
-
1
output.sync = old_sync if sync
-
-
1
t = Time.now - start
-
-
1
puts
-
1
puts
-
puts "Finished #{type}s in %.6fs, %.4f tests/s, %.4f assertions/s." %
-
1
[t, test_count / t, assertion_count / t]
-
-
1
report.each_with_index do |msg, i|
-
puts "\n%3d) %s" % [i + 1, msg]
-
end
-
-
1
puts
-
-
1
status
-
end
-
-
##
-
# Runs all the +suites+ for a given +type+. Runs suites declaring
-
# a test_order of +:parallel+ in parallel, and everything else
-
# serial.
-
-
1
def _run_suites suites, type
-
265
parallel, serial = suites.partition { |s| s.test_order == :parallel }
-
-
ParallelEach.new(parallel).map { |suite| _run_suite suite, type } +
-
265
serial.map { |suite| _run_suite suite, type }
-
end
-
-
##
-
# Run a single +suite+ for a given +type+.
-
-
1
def _run_suite suite, type
-
264
header = "#{type}_suite_header"
-
264
puts send(header, suite) if respond_to? header
-
-
264
filter = options[:filter] || '/./'
-
264
filter = Regexp.new $1 if filter =~ /\/(.*)\//
-
-
264
assertions = suite.send("#{type}_methods").grep(filter).map { |method|
-
3640
inst = suite.new method
-
3640
inst._assertions = 0
-
-
3640
print "#{suite}##{method} = " if @verbose
-
-
3640
start_time = Time.now if @verbose
-
3640
result = inst.run self
-
-
3640
print "%.2f s = " % (Time.now - start_time) if @verbose
-
3640
print result
-
3640
puts if @verbose
-
-
3640
inst._assertions
-
}
-
-
3904
return assertions.size, assertions.inject(0) { |sum, n| sum + n }
-
end
-
-
##
-
# Record the result of a single run. Makes it very easy to gather
-
# information. Eg:
-
#
-
# class StatisticsRecorder < MiniTest::Unit
-
# def record suite, method, assertions, time, error
-
# # ... record the results somewhere ...
-
# end
-
# end
-
#
-
# MiniTest::Unit.runner = StatisticsRecorder.new
-
-
1
def record suite, method, assertions, time, error
-
end
-
-
1
def location e # :nodoc:
-
last_before_assertion = ""
-
e.backtrace.reverse_each do |s|
-
break if s =~ /in .(assert|refute|flunk|pass|fail|raise|must|wont)/
-
last_before_assertion = s
-
end
-
last_before_assertion.sub(/:in .*$/, '')
-
end
-
-
##
-
# Writes status for failed test +meth+ in +klass+ which finished with
-
# exception +e+
-
-
1
def puke klass, meth, e
-
50
e = case e
-
when MiniTest::Skip then
-
50
@skips += 1
-
50
return "S" unless @verbose
-
"Skipped:\n#{meth}(#{klass}) [#{location e}]:\n#{e.message}\n"
-
when MiniTest::Assertion then
-
@failures += 1
-
"Failure:\n#{meth}(#{klass}) [#{location e}]:\n#{e.message}\n"
-
else
-
@errors += 1
-
bt = MiniTest::filter_backtrace(e.backtrace).join "\n "
-
"Error:\n#{meth}(#{klass}):\n#{e.class}: #{e.message}\n #{bt}\n"
-
end
-
@report << e
-
e[0, 1]
-
end
-
-
1
def initialize # :nodoc:
-
2
@report = []
-
2
@errors = @failures = @skips = 0
-
2
@verbose = false
-
2
@mutex = Mutex.new
-
end
-
-
1
def synchronize # :nodoc:
-
@mutex.synchronize { yield }
-
end
-
-
1
def process_args args = [] # :nodoc:
-
1
options = {}
-
1
orig_args = args.dup
-
-
1
OptionParser.new do |opts|
-
1
opts.banner = 'minitest options:'
-
1
opts.version = MiniTest::Unit::VERSION
-
-
1
opts.on '-h', '--help', 'Display this help.' do
-
puts opts
-
exit
-
end
-
-
1
opts.on '-s', '--seed SEED', Integer, "Sets random seed" do |m|
-
options[:seed] = m.to_i
-
end
-
-
1
opts.on '-v', '--verbose', "Verbose. Show progress processing files." do
-
options[:verbose] = true
-
end
-
-
1
opts.on '-n', '--name PATTERN', "Filter test names on pattern (e.g. /foo/)" do |a|
-
options[:filter] = a
-
end
-
-
1
opts.parse! args
-
1
orig_args -= args
-
end
-
-
1
unless options[:seed] then
-
1
srand
-
1
options[:seed] = srand % 0xFFFF
-
1
orig_args << "--seed" << options[:seed].to_s
-
end
-
-
1
srand options[:seed]
-
-
1
self.verbose = options[:verbose]
-
3
@help = orig_args.map { |s| s =~ /[\s|&<>$()]/ ? s.inspect : s }.join " "
-
-
1
options
-
end
-
-
##
-
# Begins the full test run. Delegates to +runner+'s #_run method.
-
-
1
def run args = []
-
1
self.class.runner._run(args)
-
end
-
-
##
-
# Top level driver, controls all output and filtering.
-
-
1
def _run args = []
-
1
self.options = process_args args
-
-
1
puts "Run options: #{help}"
-
-
1
self.class.plugins.each do |plugin|
-
1
send plugin
-
1
break unless report.empty?
-
end
-
-
1
return failures + errors if @test_count > 0 # or return nil...
-
rescue Interrupt
-
abort 'Interrupted'
-
end
-
-
##
-
# Runs test suites matching +filter+.
-
-
1
def run_tests
-
1
_run_anything :test
-
end
-
-
##
-
# Writes status to +io+
-
-
1
def status io = self.output
-
1
format = "%d tests, %d assertions, %d failures, %d errors, %d skips"
-
1
io.puts format % [test_count, assertion_count, failures, errors, skips]
-
end
-
-
##
-
# Provides a simple set of guards that you can use in your tests
-
# to skip execution if it is not applicable. These methods are
-
# mixed into TestCase as both instance and class methods so you
-
# can use them inside or outside of the test methods.
-
#
-
# def test_something_for_mri
-
# skip "bug 1234" if jruby?
-
# # ...
-
# end
-
#
-
# if windows? then
-
# # ... lots of test methods ...
-
# end
-
-
1
module Guard
-
-
##
-
# Is this running on jruby?
-
-
1
def jruby? platform = RUBY_PLATFORM
-
"java" == platform
-
end
-
-
##
-
# Is this running on mri?
-
-
1
def mri? platform = RUBY_DESCRIPTION
-
/^ruby/ =~ platform
-
end
-
-
##
-
# Is this running on rubinius?
-
-
1
def rubinius? platform = defined?(RUBY_ENGINE) && RUBY_ENGINE
-
"rbx" == platform
-
end
-
-
##
-
# Is this running on windows?
-
-
1
def windows? platform = RUBY_PLATFORM
-
/mswin|mingw/ =~ platform
-
end
-
end
-
-
##
-
# Provides before/after hooks for setup and teardown. These are
-
# meant for library writers, NOT for regular test authors. See
-
# #before_setup for an example.
-
-
1
module LifecycleHooks
-
##
-
# Runs before every test, after setup. This hook is meant for
-
# libraries to extend minitest. It is not meant to be used by
-
# test developers.
-
#
-
# See #before_setup for an example.
-
-
1
def after_setup; end
-
-
##
-
# Runs before every test, before setup. This hook is meant for
-
# libraries to extend minitest. It is not meant to be used by
-
# test developers.
-
#
-
# As a simplistic example:
-
#
-
# module MyMinitestPlugin
-
# def before_setup
-
# super
-
# # ... stuff to do before setup is run
-
# end
-
#
-
# def after_setup
-
# # ... stuff to do after setup is run
-
# super
-
# end
-
#
-
# def before_teardown
-
# super
-
# # ... stuff to do before teardown is run
-
# end
-
#
-
# def after_teardown
-
# # ... stuff to do after teardown is run
-
# super
-
# end
-
# end
-
#
-
# class MiniTest::Unit::TestCase
-
# include MyMinitestPlugin
-
# end
-
-
1
def before_setup; end
-
-
##
-
# Runs after every test, before teardown. This hook is meant for
-
# libraries to extend minitest. It is not meant to be used by
-
# test developers.
-
#
-
# See #before_setup for an example.
-
-
1
def before_teardown; end
-
-
##
-
# Runs after every test, after teardown. This hook is meant for
-
# libraries to extend minitest. It is not meant to be used by
-
# test developers.
-
#
-
# See #before_setup for an example.
-
-
1
def after_teardown; end
-
end
-
-
1
module Deprecated # :nodoc:
-
-
##
-
# This entire module is deprecated and slated for removal on 2013-01-01.
-
-
1
module Hooks
-
1
def run_setup_hooks # :nodoc:
-
_run_hooks self.class.setup_hooks
-
end
-
-
1
def _run_hooks hooks # :nodoc:
-
hooks.each do |hook|
-
if hook.respond_to?(:arity) && hook.arity == 1
-
hook.call(self)
-
else
-
hook.call
-
end
-
end
-
end
-
-
1
def run_teardown_hooks # :nodoc:
-
_run_hooks self.class.teardown_hooks.reverse
-
end
-
end
-
-
##
-
# This entire module is deprecated and slated for removal on 2013-01-01.
-
-
1
module HooksCM
-
##
-
# Adds a block of code that will be executed before every
-
# TestCase is run.
-
#
-
# NOTE: This method is deprecated, use before/after_setup. It
-
# will be removed on 2013-01-01.
-
-
1
def add_setup_hook arg=nil, &block
-
warn "NOTE: MiniTest::Unit::TestCase.add_setup_hook is deprecated, use before/after_setup via a module (and call super!). It will be removed on 2013-01-01. Called from #{caller.first}"
-
hook = arg || block
-
@setup_hooks << hook
-
end
-
-
1
def setup_hooks # :nodoc:
-
if superclass.respond_to? :setup_hooks then
-
superclass.setup_hooks
-
else
-
[]
-
end + @setup_hooks
-
end
-
-
##
-
# Adds a block of code that will be executed after every
-
# TestCase is run.
-
#
-
# NOTE: This method is deprecated, use before/after_teardown. It
-
# will be removed on 2013-01-01.
-
-
1
def add_teardown_hook arg=nil, &block
-
warn "NOTE: MiniTest::Unit::TestCase#add_teardown_hook is deprecated, use before/after_teardown. It will be removed on 2013-01-01. Called from #{caller.first}"
-
hook = arg || block
-
@teardown_hooks << hook
-
end
-
-
1
def teardown_hooks # :nodoc:
-
if superclass.respond_to? :teardown_hooks then
-
superclass.teardown_hooks
-
else
-
[]
-
end + @teardown_hooks
-
end
-
end
-
end
-
-
##
-
# Subclass TestCase to create your own tests. Typically you'll want a
-
# TestCase subclass per implementation class.
-
#
-
# See MiniTest::Assertions
-
-
1
class TestCase
-
1
include LifecycleHooks
-
1
include Deprecated::Hooks
-
1
extend Deprecated::HooksCM # UGH... I can't wait 'til 2013!
-
1
include Guard
-
1
extend Guard
-
-
1
attr_reader :__name__ # :nodoc:
-
-
1
PASSTHROUGH_EXCEPTIONS = [NoMemoryError, SignalException,
-
Interrupt, SystemExit] # :nodoc:
-
-
1
SUPPORTS_INFO_SIGNAL = Signal.list['INFO'] # :nodoc:
-
-
##
-
# Runs the tests reporting the status to +runner+
-
-
1
def run runner
-
trap "INFO" do
-
runner.report.each_with_index do |msg, i|
-
warn "\n%3d) %s" % [i + 1, msg]
-
end
-
warn ''
-
time = runner.start_time ? Time.now - runner.start_time : 0
-
warn "Current Test: %s#%s %.2fs" % [self.class, self.__name__, time]
-
runner.status $stderr
-
3640
end if SUPPORTS_INFO_SIGNAL
-
-
3640
start_time = Time.now
-
-
3640
result = ""
-
3640
begin
-
3640
@passed = nil
-
3640
self.before_setup
-
3639
self.setup
-
3598
self.after_setup
-
3598
self.run_test self.__name__
-
3590
result = "." unless io?
-
3590
time = Time.now - start_time
-
3590
runner.record self.class, self.__name__, self._assertions, time, nil
-
3590
@passed = true
-
rescue *PASSTHROUGH_EXCEPTIONS
-
raise
-
rescue Exception => e
-
50
@passed = false
-
50
time = Time.now - start_time
-
50
runner.record self.class, self.__name__, self._assertions, time, e
-
50
result = runner.puke self.class, self.__name__, e
-
ensure
-
3640
%w{ before_teardown teardown after_teardown }.each do |hook|
-
10920
begin
-
10920
self.send hook
-
rescue *PASSTHROUGH_EXCEPTIONS
-
raise
-
rescue Exception => e
-
@passed = false
-
result = runner.puke self.class, self.__name__, e
-
end
-
end
-
3640
trap 'INFO', 'DEFAULT' if SUPPORTS_INFO_SIGNAL
-
end
-
3640
result
-
end
-
-
1
alias :run_test :__send__
-
-
1
def initialize name # :nodoc:
-
3640
@__name__ = name
-
3640
@__io__ = nil
-
3640
@passed = nil
-
3640
@@current = self
-
end
-
-
1
def self.current # :nodoc:
-
@@current
-
end
-
-
##
-
# Return the output IO object
-
-
1
def io
-
@__io__ = true
-
MiniTest::Unit.output
-
end
-
-
##
-
# Have we hooked up the IO yet?
-
-
1
def io?
-
3590
@__io__
-
end
-
-
1
def self.reset # :nodoc:
-
1
@@test_suites = {}
-
end
-
-
1
reset
-
-
##
-
# Call this at the top of your tests when you absolutely
-
# positively need to have ordered tests. In doing so, you're
-
# admitting that you suck and your tests are weak.
-
-
1
def self.i_suck_and_my_tests_are_order_dependent!
-
class << self
-
undef_method :test_order if method_defined? :test_order
-
define_method :test_order do :alpha end
-
end
-
end
-
-
##
-
# Make diffs for this TestCase use #pretty_inspect so that diff
-
# in assert_equal can be more details. NOTE: this is much slower
-
# than the regular inspect but much more usable for complex
-
# objects.
-
-
1
def self.make_my_diffs_pretty!
-
require 'pp'
-
-
define_method :mu_pp do |o|
-
o.pretty_inspect
-
end
-
end
-
-
##
-
# Call this at the top of your tests when you want to run your
-
# tests in parallel. In doing so, you're admitting that you rule
-
# and your tests are awesome.
-
-
1
def self.parallelize_me!
-
class << self
-
undef_method :test_order if method_defined? :test_order
-
define_method :test_order do :parallel end
-
end
-
end
-
-
1
def self.inherited klass # :nodoc:
-
264
@@test_suites[klass] = true
-
264
klass.reset_setup_teardown_hooks
-
264
super
-
end
-
-
1
def self.test_order # :nodoc:
-
2
:random
-
end
-
-
1
def self.test_suites # :nodoc:
-
265
@@test_suites.keys.sort_by { |ts| ts.name.to_s }
-
end
-
-
1
def self.test_methods # :nodoc:
-
3904
methods = public_instance_methods(true).grep(/^test/).map { |m| m.to_s }
-
-
264
case self.test_order
-
when :parallel
-
max = methods.size
-
ParallelEach.new methods.sort.sort_by { rand max }
-
when :random then
-
1
max = methods.size
-
1
methods.sort.sort_by { rand max }
-
when :alpha, :sorted then
-
263
methods.sort
-
else
-
raise "Unknown test_order: #{self.test_order.inspect}"
-
end
-
end
-
-
##
-
# Returns true if the test passed.
-
-
1
def passed?
-
@passed
-
end
-
-
##
-
# Runs before every test. Use this to set up before each test
-
# run.
-
-
1
def setup; end
-
-
##
-
# Runs after every test. Use this to clean up after each test
-
# run.
-
-
1
def teardown; end
-
-
1
def self.reset_setup_teardown_hooks # :nodoc:
-
# also deprecated... believe it.
-
265
@setup_hooks = []
-
265
@teardown_hooks = []
-
end
-
-
1
reset_setup_teardown_hooks
-
-
1
include MiniTest::Assertions
-
end # class TestCase
-
end # class Unit
-
end # module MiniTest
-
-
1
Minitest = MiniTest # :nodoc: because ugh... I typo this all the time
-
-
1
if $DEBUG then
-
module Test # :nodoc:
-
module Unit # :nodoc:
-
class TestCase # :nodoc:
-
def self.inherited x # :nodoc:
-
# this helps me ferret out porting issues
-
raise "Using minitest and test/unit in the same process: #{x}"
-
end
-
end
-
end
-
end
-
end
-
1
module MultiJson
-
1
module Adapters
-
1
module JsonCommon
-
-
1
def load(string, options={})
-
3
string = string.read if string.respond_to?(:read)
-
3
::JSON.parse(string, :symbolize_names => options[:symbolize_keys])
-
end
-
-
1
def dump(object, options={})
-
object.to_json(process_options(options))
-
end
-
-
1
protected
-
-
1
def process_options(options={})
-
return options if options.empty?
-
opts = {}
-
opts.merge!(JSON::PRETTY_STATE_PROTOTYPE.to_h) if options.delete(:pretty)
-
opts.merge!(options)
-
end
-
-
end
-
end
-
end
-
1
require 'json' unless defined?(::JSON)
-
1
require 'multi_json/adapters/json_common'
-
-
1
module MultiJson
-
1
module Adapters
-
# Use the JSON gem to dump/load.
-
1
class JsonGem
-
1
ParseError = ::JSON::ParserError
-
1
extend JsonCommon
-
end
-
end
-
end
-
#!/usr/bin/env ruby
-
-
1
begin
-
1
require 'pg_ext'
-
rescue LoadError
-
# If it's a Windows binary gem, try the <major>.<minor> subdirectory
-
if RUBY_PLATFORM =~/(mswin|mingw)/i
-
major_minor = RUBY_VERSION[ /^(\d+\.\d+)/ ] or
-
raise "Oops, can't extract the major/minor version from #{RUBY_VERSION.dump}"
-
require "#{major_minor}/pg_ext"
-
else
-
raise
-
end
-
-
end
-
-
-
# The top-level PG namespace.
-
1
module PG
-
-
# Library version
-
1
VERSION = '0.14.1'
-
-
# VCS revision
-
1
REVISION = %q$Revision: ef533f731814 $
-
-
-
### Get the PG library version. If +include_buildnum+ is +true+, include the build ID.
-
1
def self::version_string( include_buildnum=false )
-
vstring = "%s %s" % [ self.name, VERSION ]
-
vstring << " (build %s)" % [ REVISION[/: ([[:xdigit:]]+)/, 1] || '0' ] if include_buildnum
-
return vstring
-
end
-
-
-
### Convenience alias for PG::Connection.new.
-
1
def self::connect( *args )
-
return PG::Connection.new( *args )
-
end
-
-
-
1
require 'pg/exceptions'
-
1
require 'pg/constants'
-
1
require 'pg/connection'
-
1
require 'pg/result'
-
-
end # module PG
-
-
-
# Backward-compatible aliase
-
1
PGError = PG::Error
-
-
#!/usr/bin/env ruby
-
-
1
require 'pg' unless defined?( PG )
-
-
# The PG connection class.
-
1
class PG::Connection
-
-
# The order the options are passed to the ::connect method.
-
1
CONNECT_ARGUMENT_ORDER = %w[host port options tty dbname user password]
-
-
-
### Quote the given +value+ for use in a connection-parameter string.
-
1
def self::quote_connstr( value )
-
97
return "'" + value.to_s.gsub( /[\\']/ ) {|m| '\\' + m } + "'"
-
end
-
-
-
### Parse the connection +args+ into a connection-parameter string. See PG::Connection.new
-
### for valid arguments.
-
1
def self::parse_connect_args( *args )
-
95
return '' if args.empty?
-
-
# This will be swapped soon for code that makes options like those required for
-
# PQconnectdbParams()/PQconnectStartParams(). For now, stick to an options string for
-
# PQconnectdb()/PQconnectStart().
-
95
connopts = []
-
-
# Handle an options hash first
-
95
if args.last.is_a?( Hash )
-
95
opthash = args.pop
-
95
opthash.each do |key, val|
-
97
connopts.push( "%s=%s" % [key, PG::Connection.quote_connstr(val)] )
-
end
-
end
-
-
# Option string style
-
95
if args.length == 1 && args.first.to_s.index( '=' )
-
connopts.unshift( args.first )
-
-
# Append positional parameters
-
else
-
95
args.each_with_index do |val, i|
-
next unless val # Skip nil placeholders
-
-
key = CONNECT_ARGUMENT_ORDER[ i ] or
-
raise ArgumentError, "Extra positional parameter %d: %p" % [ i+1, val ]
-
connopts.push( "%s=%s" % [key, PG::Connection.quote_connstr(val.to_s)] )
-
end
-
end
-
-
95
return connopts.join(' ')
-
end
-
-
-
# Backward-compatibility aliases for stuff that's moved into PG.
-
1
class << self
-
1
define_method( :isthreadsafe, &PG.method(:isthreadsafe) )
-
end
-
-
-
end # class PG::Connection
-
-
# Backward-compatible alias
-
1
PGconn = PG::Connection
-
-
#!/usr/bin/env ruby
-
-
1
require 'pg' unless defined?( PG )
-
-
-
1
module PG::Constants
-
-
# Most of these are defined in the extension.
-
-
end # module PG::Constants
-
-
#!/usr/bin/env ruby
-
-
1
require 'pg' unless defined?( PG )
-
-
-
1
module PG
-
-
1
class Error < StandardError; end
-
-
end # module PG
-
-
#!/usr/bin/env ruby
-
-
1
require 'pg' unless defined?( PG )
-
-
-
1
class PG::Result
-
-
end # class PG::Result
-
-
# Backward-compatible alias
-
1
PGresult = PG::Result
-
# Copyright (C) 2007, 2008, 2009, 2010 Christian Neukirchen <purl.org/net/chneukirchen>
-
#
-
# Rack is freely distributable under the terms of an MIT-style license.
-
# See COPYING or http://www.opensource.org/licenses/mit-license.php.
-
-
# The Rack main module, serving as a namespace for all core Rack
-
# modules and classes.
-
#
-
# All modules meant for use in your application are <tt>autoload</tt>ed here,
-
# so it should be enough just to <tt>require rack.rb</tt> in your code.
-
-
1
module Rack
-
# The Rack protocol version number implemented.
-
1
VERSION = [1,1]
-
-
# Return the Rack protocol version as a dotted string.
-
1
def self.version
-
VERSION.join(".")
-
end
-
-
# Return the Rack release as a dotted string.
-
1
def self.release
-
"1.4"
-
end
-
-
1
autoload :Builder, "rack/builder"
-
1
autoload :BodyProxy, "rack/body_proxy"
-
1
autoload :Cascade, "rack/cascade"
-
1
autoload :Chunked, "rack/chunked"
-
1
autoload :CommonLogger, "rack/commonlogger"
-
1
autoload :ConditionalGet, "rack/conditionalget"
-
1
autoload :Config, "rack/config"
-
1
autoload :ContentLength, "rack/content_length"
-
1
autoload :ContentType, "rack/content_type"
-
1
autoload :ETag, "rack/etag"
-
1
autoload :File, "rack/file"
-
1
autoload :Deflater, "rack/deflater"
-
1
autoload :Directory, "rack/directory"
-
1
autoload :ForwardRequest, "rack/recursive"
-
1
autoload :Handler, "rack/handler"
-
1
autoload :Head, "rack/head"
-
1
autoload :Lint, "rack/lint"
-
1
autoload :Lock, "rack/lock"
-
1
autoload :Logger, "rack/logger"
-
1
autoload :MethodOverride, "rack/methodoverride"
-
1
autoload :Mime, "rack/mime"
-
1
autoload :NullLogger, "rack/nulllogger"
-
1
autoload :Recursive, "rack/recursive"
-
1
autoload :Reloader, "rack/reloader"
-
1
autoload :Runtime, "rack/runtime"
-
1
autoload :Sendfile, "rack/sendfile"
-
1
autoload :Server, "rack/server"
-
1
autoload :ShowExceptions, "rack/showexceptions"
-
1
autoload :ShowStatus, "rack/showstatus"
-
1
autoload :Static, "rack/static"
-
1
autoload :URLMap, "rack/urlmap"
-
1
autoload :Utils, "rack/utils"
-
1
autoload :Multipart, "rack/multipart"
-
-
1
autoload :MockRequest, "rack/mock"
-
1
autoload :MockResponse, "rack/mock"
-
-
1
autoload :Request, "rack/request"
-
1
autoload :Response, "rack/response"
-
-
1
module Auth
-
1
autoload :Basic, "rack/auth/basic"
-
1
autoload :AbstractRequest, "rack/auth/abstract/request"
-
1
autoload :AbstractHandler, "rack/auth/abstract/handler"
-
1
module Digest
-
1
autoload :MD5, "rack/auth/digest/md5"
-
1
autoload :Nonce, "rack/auth/digest/nonce"
-
1
autoload :Params, "rack/auth/digest/params"
-
1
autoload :Request, "rack/auth/digest/request"
-
end
-
end
-
-
1
module Session
-
1
autoload :Cookie, "rack/session/cookie"
-
1
autoload :Pool, "rack/session/pool"
-
1
autoload :Memcache, "rack/session/memcache"
-
end
-
end
-
1
module Rack
-
1
class BodyProxy
-
1
def initialize(body, &block)
-
13
@body, @block, @closed = body, block, false
-
end
-
-
1
def respond_to?(*args)
-
1
super or @body.respond_to?(*args)
-
end
-
-
1
def close
-
5
return if @closed
-
5
@closed = true
-
5
begin
-
5
@body.close if @body.respond_to? :close
-
ensure
-
5
@block.call
-
end
-
end
-
-
1
def closed?
-
@closed
-
end
-
-
1
def method_missing(*args, &block)
-
3
@body.__send__(*args, &block)
-
end
-
end
-
end
-
# Define a package task library to aid in the definition of
-
# redistributable package files.
-
-
1
require 'rake'
-
1
require 'rake/tasklib'
-
-
1
module Rake
-
-
# Create a packaging task that will package the project into
-
# distributable files (e.g zip archive or tar files).
-
#
-
# The PackageTask will create the following targets:
-
#
-
# [<b>:package</b>]
-
# Create all the requested package files.
-
#
-
# [<b>:clobber_package</b>]
-
# Delete all the package files. This target is automatically
-
# added to the main clobber target.
-
#
-
# [<b>:repackage</b>]
-
# Rebuild the package files from scratch, even if they are not out
-
# of date.
-
#
-
# [<b>"<em>package_dir</em>/<em>name</em>-<em>version</em>.tgz"</b>]
-
# Create a gzipped tar package (if <em>need_tar</em> is true).
-
#
-
# [<b>"<em>package_dir</em>/<em>name</em>-<em>version</em>.tar.gz"</b>]
-
# Create a gzipped tar package (if <em>need_tar_gz</em> is true).
-
#
-
# [<b>"<em>package_dir</em>/<em>name</em>-<em>version</em>.tar.bz2"</b>]
-
# Create a bzip2'd tar package (if <em>need_tar_bz2</em> is true).
-
#
-
# [<b>"<em>package_dir</em>/<em>name</em>-<em>version</em>.zip"</b>]
-
# Create a zip package archive (if <em>need_zip</em> is true).
-
#
-
# Example:
-
#
-
# Rake::PackageTask.new("rake", "1.2.3") do |p|
-
# p.need_tar = true
-
# p.package_files.include("lib/**/*.rb")
-
# end
-
#
-
1
class PackageTask < TaskLib
-
# Name of the package (from the GEM Spec).
-
1
attr_accessor :name
-
-
# Version of the package (e.g. '1.3.2').
-
1
attr_accessor :version
-
-
# Directory used to store the package files (default is 'pkg').
-
1
attr_accessor :package_dir
-
-
# True if a gzipped tar file (tgz) should be produced (default is false).
-
1
attr_accessor :need_tar
-
-
# True if a gzipped tar file (tar.gz) should be produced (default is false).
-
1
attr_accessor :need_tar_gz
-
-
# True if a bzip2'd tar file (tar.bz2) should be produced (default is false).
-
1
attr_accessor :need_tar_bz2
-
-
# True if a zip file should be produced (default is false)
-
1
attr_accessor :need_zip
-
-
# List of files to be included in the package.
-
1
attr_accessor :package_files
-
-
# Tar command for gzipped or bzip2ed archives. The default is 'tar'.
-
1
attr_accessor :tar_command
-
-
# Zip command for zipped archives. The default is 'zip'.
-
1
attr_accessor :zip_command
-
-
# Create a Package Task with the given name and version. Use +:noversion+
-
# as the version to build a package without a version or to provide a
-
# fully-versioned package name.
-
-
1
def initialize(name=nil, version=nil)
-
init(name, version)
-
yield self if block_given?
-
define unless name.nil?
-
end
-
-
# Initialization that bypasses the "yield self" and "define" step.
-
1
def init(name, version)
-
1
@name = name
-
1
@version = version
-
1
@package_files = Rake::FileList.new
-
1
@package_dir = 'pkg'
-
1
@need_tar = false
-
1
@need_tar_gz = false
-
1
@need_tar_bz2 = false
-
1
@need_zip = false
-
1
@tar_command = 'tar'
-
1
@zip_command = 'zip'
-
end
-
-
# Create the tasks defined by this task library.
-
1
def define
-
1
fail "Version required (or :noversion)" if @version.nil?
-
1
@version = nil if :noversion == @version
-
-
1
desc "Build all the packages"
-
1
task :package
-
-
1
desc "Force a rebuild of the package files"
-
1
task :repackage => [:clobber_package, :package]
-
-
1
desc "Remove package products"
-
1
task :clobber_package do
-
rm_r package_dir rescue nil
-
end
-
-
1
task :clobber => [:clobber_package]
-
-
[
-
1
[need_tar, tgz_file, "z"],
-
[need_tar_gz, tar_gz_file, "z"],
-
[need_tar_bz2, tar_bz2_file, "j"]
-
].each do |(need, file, flag)|
-
3
if need
-
task :package => ["#{package_dir}/#{file}"]
-
file "#{package_dir}/#{file}" => [package_dir_path] + package_files do
-
chdir(package_dir) do
-
sh %{#{@tar_command} #{flag}cvf #{file} #{package_name}}
-
end
-
end
-
end
-
end
-
-
1
if need_zip
-
task :package => ["#{package_dir}/#{zip_file}"]
-
file "#{package_dir}/#{zip_file}" => [package_dir_path] + package_files do
-
chdir(package_dir) do
-
sh %{#{@zip_command} -r #{zip_file} #{package_name}}
-
end
-
end
-
end
-
-
1
directory package_dir
-
-
1
file package_dir_path => @package_files do
-
mkdir_p package_dir rescue nil
-
@package_files.each do |fn|
-
f = File.join(package_dir_path, fn)
-
fdir = File.dirname(f)
-
mkdir_p(fdir) if !File.exist?(fdir)
-
if File.directory?(fn)
-
mkdir_p(f)
-
else
-
rm_f f
-
safe_ln(fn, f)
-
end
-
end
-
end
-
1
self
-
end
-
-
1
def package_name
-
4
@version ? "#{@name}-#{@version}" : @name
-
end
-
-
1
def package_dir_path
-
1
"#{package_dir}/#{package_name}"
-
end
-
-
1
def tgz_file
-
1
"#{package_name}.tgz"
-
end
-
-
1
def tar_gz_file
-
1
"#{package_name}.tar.gz"
-
end
-
-
1
def tar_bz2_file
-
1
"#{package_name}.tar.bz2"
-
end
-
-
1
def zip_file
-
"#{package_name}.zip"
-
end
-
end
-
-
end
-
1
require 'rake'
-
-
1
module Rake
-
-
# Base class for Task Libraries.
-
1
class TaskLib
-
1
include Cloneable
-
1
include Rake::DSL
-
-
# Make a symbol by pasting two strings together.
-
#
-
# NOTE: DEPRECATED! This method is kinda stupid. I don't know why
-
# I didn't just use string interpolation. But now other task
-
# libraries depend on this so I can't remove it without breaking
-
# other people's code. So for now it stays for backwards
-
# compatibility. BUT DON'T USE IT.
-
1
def paste(a,b) # :nodoc:
-
(a.to_s + b.to_s).intern
-
end
-
end
-
-
end
-
#--
-
# Copyright (c) 2005-2010 Philip Ross
-
#
-
# Permission is hereby granted, free of charge, to any person obtaining a copy
-
# of this software and associated documentation files (the "Software"), to deal
-
# in the Software without restriction, including without limitation the rights
-
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-
# copies of the Software, and to permit persons to whom the Software is
-
# furnished to do so, subject to the following conditions:
-
#
-
# The above copyright notice and this permission notice shall be included in all
-
# copies or substantial portions of the Software.
-
#
-
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
-
# THE SOFTWARE.
-
#++
-
-
# Add the directory containing this file to the start of the load path if it
-
# isn't there already.
-
$:.unshift(File.dirname(__FILE__)) unless
-
1
$:.include?(File.dirname(__FILE__)) || $:.include?(File.expand_path(File.dirname(__FILE__)))
-
-
-
1
require 'tzinfo/ruby_core_support'
-
1
require 'tzinfo/offset_rationals'
-
1
require 'tzinfo/time_or_datetime'
-
-
1
require 'tzinfo/timezone_definition'
-
-
1
require 'tzinfo/timezone_offset_info'
-
1
require 'tzinfo/timezone_transition_info'
-
-
1
require 'tzinfo/timezone_index_definition'
-
-
1
require 'tzinfo/timezone_info'
-
1
require 'tzinfo/data_timezone_info'
-
1
require 'tzinfo/linked_timezone_info'
-
-
1
require 'tzinfo/timezone_period'
-
1
require 'tzinfo/timezone'
-
1
require 'tzinfo/info_timezone'
-
1
require 'tzinfo/data_timezone'
-
1
require 'tzinfo/linked_timezone'
-
1
require 'tzinfo/timezone_proxy'
-
-
1
require 'tzinfo/country_index_definition'
-
1
require 'tzinfo/country_info'
-
-
1
require 'tzinfo/country'
-
1
require 'tzinfo/country_timezone'
-
#--
-
# Copyright (c) 2005-2010 Philip Ross
-
#
-
# Permission is hereby granted, free of charge, to any person obtaining a copy
-
# of this software and associated documentation files (the "Software"), to deal
-
# in the Software without restriction, including without limitation the rights
-
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-
# copies of the Software, and to permit persons to whom the Software is
-
# furnished to do so, subject to the following conditions:
-
#
-
# The above copyright notice and this permission notice shall be included in all
-
# copies or substantial portions of the Software.
-
#
-
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
-
# THE SOFTWARE.
-
#++
-
-
1
module TZInfo
-
# Thrown by Country#get if the code given is not valid.
-
1
class InvalidCountryCode < StandardError
-
end
-
-
# An ISO 3166 country. Can be used to get a list of Timezones for a country.
-
# For example:
-
#
-
# us = Country.get('US')
-
# us.zone_identifiers
-
# us.zones
-
# us.zone_info
-
1
class Country
-
1
include Comparable
-
-
# Defined countries.
-
1
@@countries = {}
-
-
# Whether the countries index has been loaded yet.
-
1
@@index_loaded = false
-
-
# Gets a Country by its ISO 3166 code. Raises an InvalidCountryCode
-
# exception if it couldn't be found.
-
1
def self.get(identifier)
-
instance = @@countries[identifier]
-
-
unless instance
-
load_index
-
info = Indexes::Countries.countries[identifier]
-
raise InvalidCountryCode.new, 'Invalid identifier' unless info
-
instance = Country.new(info)
-
@@countries[identifier] = instance
-
end
-
-
instance
-
end
-
-
# If identifier is a CountryInfo object, initializes the Country instance,
-
# otherwise calls get(identifier).
-
1
def self.new(identifier)
-
if identifier.kind_of?(CountryInfo)
-
instance = super()
-
instance.send :setup, identifier
-
instance
-
else
-
get(identifier)
-
end
-
end
-
-
# Returns an Array of all the valid country codes.
-
1
def self.all_codes
-
load_index
-
Indexes::Countries.countries.keys
-
end
-
-
# Returns an Array of all the defined Countries.
-
1
def self.all
-
load_index
-
Indexes::Countries.countries.keys.collect {|code| get(code)}
-
end
-
-
# The ISO 3166 country code.
-
1
def code
-
@info.code
-
end
-
-
# The name of the country.
-
1
def name
-
@info.name
-
end
-
-
# Alias for name.
-
1
def to_s
-
name
-
end
-
-
# Returns internal object state as a programmer-readable string.
-
1
def inspect
-
"#<#{self.class}: #{@info.code}>"
-
end
-
-
# Returns a frozen array of all the zone identifiers for the country. These
-
# are in an order that
-
# (1) makes some geographical sense, and
-
# (2) puts the most populous zones first, where that does not contradict (1).
-
1
def zone_identifiers
-
@info.zone_identifiers
-
end
-
1
alias zone_names zone_identifiers
-
-
# An array of all the Timezones for this country. Returns TimezoneProxy
-
# objects to avoid the overhead of loading Timezone definitions until
-
# a conversion is actually required. The Timezones are returned in an order
-
# that
-
# (1) makes some geographical sense, and
-
# (2) puts the most populous zones first, where that does not contradict (1).
-
1
def zones
-
zone_identifiers.collect {|id|
-
Timezone.get_proxy(id)
-
}
-
end
-
-
# Returns a frozen array of all the timezones for the for the country as
-
# CountryTimezone instances (containing extra information about each zone).
-
# These are in an order that
-
# (1) makes some geographical sense, and
-
# (2) puts the most populous zones first, where that does not contradict (1).
-
1
def zone_info
-
@info.zones
-
end
-
-
# Compare two Countries based on their code. Returns -1 if c is less
-
# than self, 0 if c is equal to self and +1 if c is greater than self.
-
1
def <=>(c)
-
code <=> c.code
-
end
-
-
# Returns true if and only if the code of c is equal to the code of this
-
# Country.
-
1
def eql?(c)
-
self == c
-
end
-
-
# Returns a hash value for this Country.
-
1
def hash
-
code.hash
-
end
-
-
# Dumps this Country for marshalling.
-
1
def _dump(limit)
-
code
-
end
-
-
# Loads a marshalled Country.
-
1
def self._load(data)
-
Country.get(data)
-
end
-
-
1
private
-
# Loads in the index of countries if it hasn't already been loaded.
-
1
def self.load_index
-
unless @@index_loaded
-
require 'tzinfo/indexes/countries'
-
@@index_loaded = true
-
end
-
end
-
-
# Called by Country.new to initialize a new Country instance. The info
-
# parameter is a CountryInfo that defines the country.
-
1
def setup(info)
-
@info = info
-
end
-
end
-
end
-
#--
-
# Copyright (c) 2006-2010 Philip Ross
-
#
-
# Permission is hereby granted, free of charge, to any person obtaining a copy
-
# of this software and associated documentation files (the "Software"), to deal
-
# in the Software without restriction, including without limitation the rights
-
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-
# copies of the Software, and to permit persons to whom the Software is
-
# furnished to do so, subject to the following conditions:
-
#
-
# The above copyright notice and this permission notice shall be included in all
-
# copies or substantial portions of the Software.
-
#
-
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
-
# THE SOFTWARE.
-
#++
-
-
1
module TZInfo
-
# The country index file includes CountryIndexDefinition which provides
-
# a country method used to define each country in the index.
-
1
module CountryIndexDefinition #:nodoc:
-
1
def self.append_features(base)
-
super
-
base.extend(ClassMethods)
-
base.instance_eval { @countries = {} }
-
end
-
-
1
module ClassMethods #:nodoc:
-
# Defines a country with an ISO 3166 country code, name and block. The
-
# block will be evaluated to obtain all the timezones for the country.
-
# Calls Country.country_defined with the definition of each country.
-
1
def country(code, name, &block)
-
@countries[code] = CountryInfo.new(code, name, &block)
-
end
-
-
# Returns a frozen hash of all the countries that have been defined in
-
# the index.
-
1
def countries
-
@countries.freeze
-
end
-
end
-
end
-
end
-
#--
-
# Copyright (c) 2006-2010 Philip Ross
-
#
-
# Permission is hereby granted, free of charge, to any person obtaining a copy
-
# of this software and associated documentation files (the "Software"), to deal
-
# in the Software without restriction, including without limitation the rights
-
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-
# copies of the Software, and to permit persons to whom the Software is
-
# furnished to do so, subject to the following conditions:
-
#
-
# The above copyright notice and this permission notice shall be included in all
-
# copies or substantial portions of the Software.
-
#
-
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
-
# THE SOFTWARE.
-
#++
-
-
1
module TZInfo
-
# Class to store the data loaded from the country index. Instances of this
-
# class are passed to the blocks in the index that define timezones.
-
1
class CountryInfo #:nodoc:
-
1
attr_reader :code
-
1
attr_reader :name
-
-
# Constructs a new CountryInfo with an ISO 3166 country code, name and
-
# block. The block will be evaluated to obtain the timezones for the country
-
# (when they are first needed).
-
1
def initialize(code, name, &block)
-
@code = code
-
@name = name
-
@block = block
-
@zones = nil
-
@zone_identifiers = nil
-
end
-
-
# Called by the index data to define a timezone for the country.
-
1
def timezone(identifier, latitude_numerator, latitude_denominator,
-
longitude_numerator, longitude_denominator, description = nil)
-
# Currently only store the identifiers.
-
@zones << CountryTimezone.new(identifier, latitude_numerator,
-
latitude_denominator, longitude_numerator, longitude_denominator,
-
description)
-
end
-
-
# Returns a frozen array of all the zone identifiers for the country. These
-
# are in the order they were added using the timezone method.
-
1
def zone_identifiers
-
unless @zone_identifiers
-
@zone_identifiers = zones.collect {|zone| zone.identifier}
-
@zone_identifiers.freeze
-
end
-
-
@zone_identifiers
-
end
-
-
# Returns internal object state as a programmer-readable string.
-
1
def inspect
-
"#<#{self.class}: #@code>"
-
end
-
-
# Returns a frozen array of all the timezones for the for the country as
-
# CountryTimezone instances. These are in the order they were added using
-
# the timezone method.
-
1
def zones
-
unless @zones
-
@zones = []
-
@block.call(self) if @block
-
@block = nil
-
@zones.freeze
-
end
-
-
@zones
-
end
-
end
-
end
-
#--
-
# Copyright (c) 2006-2010 Philip Ross
-
#
-
# Permission is hereby granted, free of charge, to any person obtaining a copy
-
# of this software and associated documentation files (the "Software"), to deal
-
# in the Software without restriction, including without limitation the rights
-
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-
# copies of the Software, and to permit persons to whom the Software is
-
# furnished to do so, subject to the following conditions:
-
#
-
# The above copyright notice and this permission notice shall be included in all
-
# copies or substantial portions of the Software.
-
#
-
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
-
# THE SOFTWARE.
-
#++
-
-
1
module TZInfo
-
# A Timezone within a Country. This contains extra information about the
-
# Timezone that is specific to the Country (a Timezone could be used by
-
# multiple countries).
-
1
class CountryTimezone
-
# The zone identifier.
-
1
attr_reader :identifier
-
-
# A description of this timezone in relation to the country, e.g.
-
# "Eastern Time". This is usually nil for countries having only a single
-
# Timezone.
-
1
attr_reader :description
-
-
# Creates a new CountryTimezone with a timezone identifier, latitude,
-
# longitude and description. The latitude and longitude are specified as
-
# rationals - a numerator and denominator. For performance reasons, the
-
# numerators and denominators must be specified in their lowest form.
-
#
-
# CountryTimezone instances should not normally be constructed manually.
-
1
def initialize(identifier, latitude_numerator, latitude_denominator,
-
longitude_numerator, longitude_denominator, description = nil) #:nodoc:
-
@identifier = identifier
-
@latitude_numerator = latitude_numerator
-
@latitude_denominator = latitude_denominator
-
@longitude_numerator = longitude_numerator
-
@longitude_denominator = longitude_denominator
-
@description = description
-
end
-
-
# The Timezone (actually a TimezoneProxy for performance reasons).
-
1
def timezone
-
Timezone.get_proxy(@identifier)
-
end
-
-
# if description is not nil, this method returns description; otherwise it
-
# returns timezone.friendly_identifier(true).
-
1
def description_or_friendly_identifier
-
description || timezone.friendly_identifier(true)
-
end
-
-
# The latitude of this timezone in degrees as a Rational.
-
1
def latitude
-
@latitude ||= RubyCoreSupport.rational_new!(@latitude_numerator, @latitude_denominator)
-
end
-
-
# The longitude of this timezone in degrees as a Rational.
-
1
def longitude
-
@longitude ||= RubyCoreSupport.rational_new!(@longitude_numerator, @longitude_denominator)
-
end
-
-
# Returns true if and only if the given CountryTimezone is equal to the
-
# current CountryTimezone (has the same identifer, latitude, longitude
-
# and description).
-
1
def ==(ct)
-
ct.respond_to?(:identifier) && ct.respond_to?(:latitude) &&
-
ct.respond_to?(:longitude) && ct.respond_to?(:description) &&
-
identifier == ct.identifier && latitude == ct.latitude &&
-
longitude == ct.longitude && description == ct.description
-
end
-
-
# Returns true if and only if the given CountryTimezone is equal to the
-
# current CountryTimezone (has the same identifer, latitude, longitude
-
# and description).
-
1
def eql?(ct)
-
self == ct
-
end
-
-
# Returns a hash of this CountryTimezone.
-
1
def hash
-
@identifier.hash ^ @latitude_numerator.hash ^ @latitude_denominator.hash ^
-
@longitude_numerator.hash ^ @longitude_denominator.hash ^ @description.hash
-
end
-
-
# Returns internal object state as a programmer-readable string.
-
1
def inspect
-
"#<#{self.class}: #@identifier>"
-
end
-
end
-
end
-
#--
-
# Copyright (c) 2006-2010 Philip Ross
-
#
-
# Permission is hereby granted, free of charge, to any person obtaining a copy
-
# of this software and associated documentation files (the "Software"), to deal
-
# in the Software without restriction, including without limitation the rights
-
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-
# copies of the Software, and to permit persons to whom the Software is
-
# furnished to do so, subject to the following conditions:
-
#
-
# The above copyright notice and this permission notice shall be included in all
-
# copies or substantial portions of the Software.
-
#
-
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
-
# THE SOFTWARE.
-
#++
-
-
1
module TZInfo
-
-
# A Timezone based on a DataTimezoneInfo.
-
1
class DataTimezone < InfoTimezone #:nodoc:
-
-
# Returns the TimezonePeriod for the given UTC time. utc can either be
-
# a DateTime, Time or integer timestamp (Time.to_i). Any timezone
-
# information in utc is ignored (it is treated as a UTC time).
-
#
-
# If no TimezonePeriod could be found, PeriodNotFound is raised.
-
1
def period_for_utc(utc)
-
222
info.period_for_utc(utc)
-
end
-
-
# Returns the set of TimezonePeriod instances that are valid for the given
-
# local time as an array. If you just want a single period, use
-
# period_for_local instead and specify how abiguities should be resolved.
-
# Raises PeriodNotFound if no periods are found for the given time.
-
1
def periods_for_local(local)
-
126
info.periods_for_local(local)
-
end
-
end
-
end
-
#--
-
# Copyright (c) 2006-2010 Philip Ross
-
#
-
# Permission is hereby granted, free of charge, to any person obtaining a copy
-
# of this software and associated documentation files (the "Software"), to deal
-
# in the Software without restriction, including without limitation the rights
-
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-
# copies of the Software, and to permit persons to whom the Software is
-
# furnished to do so, subject to the following conditions:
-
#
-
# The above copyright notice and this permission notice shall be included in all
-
# copies or substantial portions of the Software.
-
#
-
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
-
# THE SOFTWARE.
-
#++
-
-
1
module TZInfo
-
# Thrown if no offsets have been defined when calling period_for_utc or
-
# periods_for_local. Indicates an error in the timezone data.
-
1
class NoOffsetsDefined < StandardError
-
end
-
-
# Represents a (non-linked) timezone defined in a data module.
-
1
class DataTimezoneInfo < TimezoneInfo #:nodoc:
-
-
# Constructs a new TimezoneInfo with its identifier.
-
1
def initialize(identifier)
-
122
super(identifier)
-
122
@offsets = {}
-
122
@transitions = []
-
122
@previous_offset = nil
-
122
@transitions_index = nil
-
end
-
-
# Defines a offset. The id uniquely identifies this offset within the
-
# timezone. utc_offset and std_offset define the offset in seconds of
-
# standard time from UTC and daylight savings from standard time
-
# respectively. abbreviation describes the timezone offset (e.g. GMT, BST,
-
# EST or EDT).
-
#
-
# The first offset to be defined is treated as the offset that applies
-
# until the first transition. This will usually be in Local Mean Time (LMT).
-
#
-
# ArgumentError will be raised if the id is already defined.
-
1
def offset(id, utc_offset, std_offset, abbreviation)
-
610
raise ArgumentError, 'Offset already defined' if @offsets.has_key?(id)
-
-
610
offset = TimezoneOffsetInfo.new(utc_offset, std_offset, abbreviation)
-
610
@offsets[id] = offset
-
610
@previous_offset = offset unless @previous_offset
-
end
-
-
# Defines a transition. Transitions must be defined in chronological order.
-
# ArgumentError will be raised if a transition is added out of order.
-
# offset_id refers to an id defined with offset. ArgumentError will be
-
# raised if the offset_id cannot be found. numerator_or_time and
-
# denomiator specify the time the transition occurs as. See
-
# TimezoneTransitionInfo for more detail about specifying times.
-
1
def transition(year, month, offset_id, numerator_or_time, denominator = nil)
-
10791
offset = @offsets[offset_id]
-
10791
raise ArgumentError, 'Offset not found' unless offset
-
-
10791
if @transitions_index
-
10671
if year < @last_year || (year == @last_year && month < @last_month)
-
raise ArgumentError, 'Transitions must be increasing date order'
-
end
-
-
# Record the position of the first transition with this index.
-
10671
index = transition_index(year, month)
-
10671
@transitions_index[index] ||= @transitions.length
-
-
# Fill in any gaps
-
10671
(index - 1).downto(0) do |i|
-
27639
break if @transitions_index[i]
-
16968
@transitions_index[i] = @transitions.length
-
end
-
else
-
120
@transitions_index = [@transitions.length]
-
120
@start_year = year
-
120
@start_month = month
-
end
-
-
@transitions << TimezoneTransitionInfo.new(offset, @previous_offset,
-
10791
numerator_or_time, denominator)
-
10791
@last_year = year
-
10791
@last_month = month
-
10791
@previous_offset = offset
-
end
-
-
# Returns the TimezonePeriod for the given UTC time.
-
# Raises NoOffsetsDefined if no offsets have been defined.
-
1
def period_for_utc(utc)
-
222
unless @transitions.empty?
-
220
utc = TimeOrDateTime.wrap(utc)
-
220
index = transition_index(utc.year, utc.mon)
-
-
220
start_transition = nil
-
220
start = transition_before_end(index)
-
220
if start
-
220
start.downto(0) do |i|
-
264
if @transitions[i].at <= utc
-
220
start_transition = @transitions[i]
-
220
break
-
end
-
end
-
end
-
-
220
end_transition = nil
-
220
start = transition_after_start(index)
-
220
if start
-
126
start.upto(@transitions.length - 1) do |i|
-
210
if @transitions[i].at > utc
-
126
end_transition = @transitions[i]
-
126
break
-
end
-
end
-
end
-
-
220
if start_transition || end_transition
-
220
TimezonePeriod.new(start_transition, end_transition)
-
else
-
# Won't happen since there are transitions. Must always find one
-
# transition that is either >= or < the specified time.
-
raise 'No transitions found in search'
-
end
-
else
-
2
raise NoOffsetsDefined, 'No offsets have been defined' unless @previous_offset
-
2
TimezonePeriod.new(nil, nil, @previous_offset)
-
end
-
end
-
-
# Returns the set of TimezonePeriods for the given local time as an array.
-
# Results returned are ordered by increasing UTC start date.
-
# Returns an empty array if no periods are found for the given time.
-
# Raises NoOffsetsDefined if no offsets have been defined.
-
1
def periods_for_local(local)
-
126
unless @transitions.empty?
-
126
local = TimeOrDateTime.wrap(local)
-
126
index = transition_index(local.year, local.mon)
-
-
126
result = []
-
-
126
start_index = transition_after_start(index - 1)
-
126
if start_index && @transitions[start_index].local_end > local
-
6
if start_index > 0
-
6
if @transitions[start_index - 1].local_start <= local
-
6
result << TimezonePeriod.new(@transitions[start_index - 1], @transitions[start_index])
-
end
-
else
-
result << TimezonePeriod.new(nil, @transitions[start_index])
-
end
-
end
-
-
126
end_index = transition_before_end(index + 1)
-
-
126
if end_index
-
126
start_index = end_index unless start_index
-
-
126
start_index.upto(transition_before_end(index + 1)) do |i|
-
288
if @transitions[i].local_start <= local
-
160
if i + 1 < @transitions.length
-
118
if @transitions[i + 1].local_end > local
-
78
result << TimezonePeriod.new(@transitions[i], @transitions[i + 1])
-
end
-
else
-
42
result << TimezonePeriod.new(@transitions[i], nil)
-
end
-
end
-
end
-
end
-
-
126
result
-
else
-
raise NoOffsetsDefined, 'No offsets have been defined' unless @previous_offset
-
[TimezonePeriod.new(nil, nil, @previous_offset)]
-
end
-
end
-
-
1
private
-
# Returns the index into the @transitions_index array for a given year
-
# and month.
-
1
def transition_index(year, month)
-
11017
index = (year - @start_year) * 2
-
11017
index += 1 if month > 6
-
11017
index -= 1 if @start_month > 6
-
11017
index
-
end
-
-
# Returns the index into @transitions of the first transition that occurs
-
# on or after the start of the given index into @transitions_index.
-
# Returns nil if there are no such transitions.
-
1
def transition_after_start(index)
-
346
if index >= @transitions_index.length
-
nil
-
else
-
213
index = 0 if index < 0
-
213
@transitions_index[index]
-
end
-
end
-
-
# Returns the index into @transitions of the first transition that occurs
-
# before the end of the given index into @transitions_index.
-
# Returns nil if there are no such transitions.
-
1
def transition_before_end(index)
-
472
index = index + 1
-
-
472
if index <= 0
-
nil
-
472
elsif index >= @transitions_index.length
-
178
@transitions.length - 1
-
else
-
294
@transitions_index[index] - 1
-
end
-
end
-
end
-
end
-
1
module TZInfo
-
1
module Definitions
-
1
module Africa
-
1
module Algiers
-
1
include TimezoneDefinition
-
-
1
timezone 'Africa/Algiers' do |tz|
-
1
tz.offset :o0, 732, 0, :LMT
-
1
tz.offset :o1, 561, 0, :PMT
-
1
tz.offset :o2, 0, 0, :WET
-
1
tz.offset :o3, 0, 3600, :WEST
-
1
tz.offset :o4, 3600, 0, :CET
-
1
tz.offset :o5, 3600, 3600, :CEST
-
-
1
tz.transition 1891, 3, :o1, 2170625843, 900
-
1
tz.transition 1911, 3, :o2, 69670267013, 28800
-
1
tz.transition 1916, 6, :o3, 58104707, 24
-
1
tz.transition 1916, 10, :o2, 58107323, 24
-
1
tz.transition 1917, 3, :o3, 58111499, 24
-
1
tz.transition 1917, 10, :o2, 58116227, 24
-
1
tz.transition 1918, 3, :o3, 58119899, 24
-
1
tz.transition 1918, 10, :o2, 58124963, 24
-
1
tz.transition 1919, 3, :o3, 58128467, 24
-
1
tz.transition 1919, 10, :o2, 58133699, 24
-
1
tz.transition 1920, 2, :o3, 58136867, 24
-
1
tz.transition 1920, 10, :o2, 58142915, 24
-
1
tz.transition 1921, 3, :o3, 58146323, 24
-
1
tz.transition 1921, 6, :o2, 58148699, 24
-
1
tz.transition 1939, 9, :o3, 58308443, 24
-
1
tz.transition 1939, 11, :o2, 4859173, 2
-
1
tz.transition 1940, 2, :o4, 29156215, 12
-
1
tz.transition 1944, 4, :o5, 58348405, 24
-
1
tz.transition 1944, 10, :o4, 4862743, 2
-
1
tz.transition 1945, 4, :o5, 58357141, 24
-
1
tz.transition 1945, 9, :o4, 58361147, 24
-
1
tz.transition 1946, 10, :o2, 58370411, 24
-
1
tz.transition 1956, 1, :o4, 4871003, 2
-
1
tz.transition 1963, 4, :o2, 58515203, 24
-
1
tz.transition 1971, 4, :o3, 41468400
-
1
tz.transition 1971, 9, :o2, 54774000
-
1
tz.transition 1977, 5, :o3, 231724800
-
1
tz.transition 1977, 10, :o4, 246236400
-
1
tz.transition 1978, 3, :o5, 259545600
-
1
tz.transition 1978, 9, :o4, 275274000
-
1
tz.transition 1979, 10, :o2, 309740400
-
1
tz.transition 1980, 4, :o3, 325468800
-
1
tz.transition 1980, 10, :o2, 341802000
-
1
tz.transition 1981, 5, :o4, 357523200
-
end
-
end
-
end
-
end
-
end
-
1
module TZInfo
-
1
module Definitions
-
1
module Africa
-
1
module Cairo
-
1
include TimezoneDefinition
-
-
1
timezone 'Africa/Cairo' do |tz|
-
1
tz.offset :o0, 7500, 0, :LMT
-
1
tz.offset :o1, 7200, 0, :EET
-
1
tz.offset :o2, 7200, 3600, :EEST
-
-
1
tz.transition 1900, 9, :o1, 695604503, 288
-
1
tz.transition 1940, 7, :o2, 29157905, 12
-
1
tz.transition 1940, 9, :o1, 19439227, 8
-
1
tz.transition 1941, 4, :o2, 29161193, 12
-
1
tz.transition 1941, 9, :o1, 19442027, 8
-
1
tz.transition 1942, 3, :o2, 29165405, 12
-
1
tz.transition 1942, 10, :o1, 19445275, 8
-
1
tz.transition 1943, 3, :o2, 29169785, 12
-
1
tz.transition 1943, 10, :o1, 19448235, 8
-
1
tz.transition 1944, 3, :o2, 29174177, 12
-
1
tz.transition 1944, 10, :o1, 19451163, 8
-
1
tz.transition 1945, 4, :o2, 29178737, 12
-
1
tz.transition 1945, 10, :o1, 19454083, 8
-
1
tz.transition 1957, 5, :o2, 29231621, 12
-
1
tz.transition 1957, 9, :o1, 19488899, 8
-
1
tz.transition 1958, 4, :o2, 29235893, 12
-
1
tz.transition 1958, 9, :o1, 19491819, 8
-
1
tz.transition 1959, 4, :o2, 58480547, 24
-
1
tz.transition 1959, 9, :o1, 4873683, 2
-
1
tz.transition 1960, 4, :o2, 58489331, 24
-
1
tz.transition 1960, 9, :o1, 4874415, 2
-
1
tz.transition 1961, 4, :o2, 58498091, 24
-
1
tz.transition 1961, 9, :o1, 4875145, 2
-
1
tz.transition 1962, 4, :o2, 58506851, 24
-
1
tz.transition 1962, 9, :o1, 4875875, 2
-
1
tz.transition 1963, 4, :o2, 58515611, 24
-
1
tz.transition 1963, 9, :o1, 4876605, 2
-
1
tz.transition 1964, 4, :o2, 58524395, 24
-
1
tz.transition 1964, 9, :o1, 4877337, 2
-
1
tz.transition 1965, 4, :o2, 58533155, 24
-
1
tz.transition 1965, 9, :o1, 4878067, 2
-
1
tz.transition 1966, 4, :o2, 58541915, 24
-
1
tz.transition 1966, 10, :o1, 4878799, 2
-
1
tz.transition 1967, 4, :o2, 58550675, 24
-
1
tz.transition 1967, 10, :o1, 4879529, 2
-
1
tz.transition 1968, 4, :o2, 58559459, 24
-
1
tz.transition 1968, 10, :o1, 4880261, 2
-
1
tz.transition 1969, 4, :o2, 58568219, 24
-
1
tz.transition 1969, 10, :o1, 4880991, 2
-
1
tz.transition 1970, 4, :o2, 10364400
-
1
tz.transition 1970, 10, :o1, 23587200
-
1
tz.transition 1971, 4, :o2, 41900400
-
1
tz.transition 1971, 10, :o1, 55123200
-
1
tz.transition 1972, 4, :o2, 73522800
-
1
tz.transition 1972, 10, :o1, 86745600
-
1
tz.transition 1973, 4, :o2, 105058800
-
1
tz.transition 1973, 10, :o1, 118281600
-
1
tz.transition 1974, 4, :o2, 136594800
-
1
tz.transition 1974, 10, :o1, 149817600
-
1
tz.transition 1975, 4, :o2, 168130800
-
1
tz.transition 1975, 10, :o1, 181353600
-
1
tz.transition 1976, 4, :o2, 199753200
-
1
tz.transition 1976, 10, :o1, 212976000
-
1
tz.transition 1977, 4, :o2, 231289200
-
1
tz.transition 1977, 10, :o1, 244512000
-
1
tz.transition 1978, 4, :o2, 262825200
-
1
tz.transition 1978, 10, :o1, 276048000
-
1
tz.transition 1979, 4, :o2, 294361200
-
1
tz.transition 1979, 10, :o1, 307584000
-
1
tz.transition 1980, 4, :o2, 325983600
-
1
tz.transition 1980, 10, :o1, 339206400
-
1
tz.transition 1981, 4, :o2, 357519600
-
1
tz.transition 1981, 10, :o1, 370742400
-
1
tz.transition 1982, 7, :o2, 396399600
-
1
tz.transition 1982, 10, :o1, 402278400
-
1
tz.transition 1983, 7, :o2, 426812400
-
1
tz.transition 1983, 10, :o1, 433814400
-
1
tz.transition 1984, 4, :o2, 452214000
-
1
tz.transition 1984, 10, :o1, 465436800
-
1
tz.transition 1985, 4, :o2, 483750000
-
1
tz.transition 1985, 10, :o1, 496972800
-
1
tz.transition 1986, 4, :o2, 515286000
-
1
tz.transition 1986, 10, :o1, 528508800
-
1
tz.transition 1987, 4, :o2, 546822000
-
1
tz.transition 1987, 10, :o1, 560044800
-
1
tz.transition 1988, 4, :o2, 578444400
-
1
tz.transition 1988, 10, :o1, 591667200
-
1
tz.transition 1989, 5, :o2, 610412400
-
1
tz.transition 1989, 10, :o1, 623203200
-
1
tz.transition 1990, 4, :o2, 641516400
-
1
tz.transition 1990, 10, :o1, 654739200
-
1
tz.transition 1991, 4, :o2, 673052400
-
1
tz.transition 1991, 10, :o1, 686275200
-
1
tz.transition 1992, 4, :o2, 704674800
-
1
tz.transition 1992, 10, :o1, 717897600
-
1
tz.transition 1993, 4, :o2, 736210800
-
1
tz.transition 1993, 10, :o1, 749433600
-
1
tz.transition 1994, 4, :o2, 767746800
-
1
tz.transition 1994, 10, :o1, 780969600
-
1
tz.transition 1995, 4, :o2, 799020000
-
1
tz.transition 1995, 9, :o1, 812322000
-
1
tz.transition 1996, 4, :o2, 830469600
-
1
tz.transition 1996, 9, :o1, 843771600
-
1
tz.transition 1997, 4, :o2, 861919200
-
1
tz.transition 1997, 9, :o1, 875221200
-
1
tz.transition 1998, 4, :o2, 893368800
-
1
tz.transition 1998, 9, :o1, 906670800
-
1
tz.transition 1999, 4, :o2, 925423200
-
1
tz.transition 1999, 9, :o1, 938725200
-
1
tz.transition 2000, 4, :o2, 956872800
-
1
tz.transition 2000, 9, :o1, 970174800
-
1
tz.transition 2001, 4, :o2, 988322400
-
1
tz.transition 2001, 9, :o1, 1001624400
-
1
tz.transition 2002, 4, :o2, 1019772000
-
1
tz.transition 2002, 9, :o1, 1033074000
-
1
tz.transition 2003, 4, :o2, 1051221600
-
1
tz.transition 2003, 9, :o1, 1064523600
-
1
tz.transition 2004, 4, :o2, 1083276000
-
1
tz.transition 2004, 9, :o1, 1096578000
-
1
tz.transition 2005, 4, :o2, 1114725600
-
1
tz.transition 2005, 9, :o1, 1128027600
-
1
tz.transition 2006, 4, :o2, 1146175200
-
1
tz.transition 2006, 9, :o1, 1158872400
-
1
tz.transition 2007, 4, :o2, 1177624800
-
1
tz.transition 2007, 9, :o1, 1189112400
-
1
tz.transition 2008, 4, :o2, 1209074400
-
1
tz.transition 2008, 8, :o1, 1219957200
-
1
tz.transition 2009, 4, :o2, 1240524000
-
1
tz.transition 2009, 8, :o1, 1250802000
-
1
tz.transition 2010, 4, :o2, 1272578400
-
1
tz.transition 2010, 8, :o1, 1281474000
-
1
tz.transition 2010, 9, :o2, 1284069600
-
1
tz.transition 2010, 9, :o1, 1285880400
-
end
-
end
-
end
-
end
-
end
-
1
module TZInfo
-
1
module Definitions
-
1
module Africa
-
1
module Casablanca
-
1
include TimezoneDefinition
-
-
1
timezone 'Africa/Casablanca' do |tz|
-
1
tz.offset :o0, -1820, 0, :LMT
-
1
tz.offset :o1, 0, 0, :WET
-
1
tz.offset :o2, 0, 3600, :WEST
-
1
tz.offset :o3, 3600, 0, :CET
-
-
1
tz.transition 1913, 10, :o1, 10454687371, 4320
-
1
tz.transition 1939, 9, :o2, 4859037, 2
-
1
tz.transition 1939, 11, :o1, 58310075, 24
-
1
tz.transition 1940, 2, :o2, 4859369, 2
-
1
tz.transition 1945, 11, :o1, 58362659, 24
-
1
tz.transition 1950, 6, :o2, 4866887, 2
-
1
tz.transition 1950, 10, :o1, 58406003, 24
-
1
tz.transition 1967, 6, :o2, 2439645, 1
-
1
tz.transition 1967, 9, :o1, 58554347, 24
-
1
tz.transition 1974, 6, :o2, 141264000
-
1
tz.transition 1974, 8, :o1, 147222000
-
1
tz.transition 1976, 5, :o2, 199756800
-
1
tz.transition 1976, 7, :o1, 207702000
-
1
tz.transition 1977, 5, :o2, 231292800
-
1
tz.transition 1977, 9, :o1, 244249200
-
1
tz.transition 1978, 6, :o2, 265507200
-
1
tz.transition 1978, 8, :o1, 271033200
-
1
tz.transition 1984, 3, :o3, 448243200
-
1
tz.transition 1985, 12, :o1, 504918000
-
1
tz.transition 2008, 6, :o2, 1212278400
-
1
tz.transition 2008, 8, :o1, 1220223600
-
1
tz.transition 2009, 6, :o2, 1243814400
-
1
tz.transition 2009, 8, :o1, 1250809200
-
1
tz.transition 2010, 5, :o2, 1272758400
-
1
tz.transition 2010, 8, :o1, 1281222000
-
1
tz.transition 2011, 4, :o2, 1301788800
-
1
tz.transition 2011, 7, :o1, 1312066800
-
1
tz.transition 2012, 4, :o2, 1335664800
-
1
tz.transition 2012, 7, :o1, 1342749600
-
1
tz.transition 2012, 8, :o2, 1345428000
-
1
tz.transition 2012, 9, :o1, 1348970400
-
1
tz.transition 2013, 4, :o2, 1367114400
-
1
tz.transition 2013, 9, :o1, 1380420000
-
1
tz.transition 2014, 4, :o2, 1398564000
-
1
tz.transition 2014, 9, :o1, 1411869600
-
1
tz.transition 2015, 4, :o2, 1430013600
-
1
tz.transition 2015, 9, :o1, 1443319200
-
1
tz.transition 2016, 4, :o2, 1461463200
-
1
tz.transition 2016, 9, :o1, 1474768800
-
1
tz.transition 2017, 4, :o2, 1493517600
-
1
tz.transition 2017, 9, :o1, 1506218400
-
1
tz.transition 2018, 4, :o2, 1524967200
-
1
tz.transition 2018, 9, :o1, 1538272800
-
1
tz.transition 2019, 4, :o2, 1556416800
-
1
tz.transition 2019, 9, :o1, 1569722400
-
1
tz.transition 2020, 4, :o2, 1587866400
-
1
tz.transition 2020, 9, :o1, 1601172000
-
1
tz.transition 2021, 4, :o2, 1619316000
-
1
tz.transition 2021, 9, :o1, 1632621600
-
1
tz.transition 2022, 4, :o2, 1650765600
-
1
tz.transition 2022, 9, :o1, 1664071200
-
1
tz.transition 2023, 4, :o2, 1682820000
-
1
tz.transition 2023, 9, :o1, 1695520800
-
1
tz.transition 2024, 4, :o2, 1714269600
-
1
tz.transition 2024, 9, :o1, 1727575200
-
1
tz.transition 2025, 4, :o2, 1745719200
-
1
tz.transition 2025, 9, :o1, 1759024800
-
1
tz.transition 2026, 4, :o2, 1777168800
-
1
tz.transition 2026, 9, :o1, 1790474400
-
1
tz.transition 2027, 4, :o2, 1808618400
-
1
tz.transition 2027, 9, :o1, 1821924000
-
1
tz.transition 2028, 4, :o2, 1840672800
-
1
tz.transition 2028, 9, :o1, 1853373600
-
1
tz.transition 2029, 4, :o2, 1872122400
-
1
tz.transition 2029, 9, :o1, 1885428000
-
1
tz.transition 2030, 4, :o2, 1903572000
-
1
tz.transition 2030, 9, :o1, 1916877600
-
1
tz.transition 2031, 4, :o2, 1935021600
-
1
tz.transition 2031, 9, :o1, 1948327200
-
1
tz.transition 2032, 4, :o2, 1966471200
-
1
tz.transition 2032, 9, :o1, 1979776800
-
1
tz.transition 2033, 4, :o2, 1997920800
-
1
tz.transition 2033, 9, :o1, 2011226400
-
1
tz.transition 2034, 4, :o2, 2029975200
-
1
tz.transition 2034, 9, :o1, 2042676000
-
1
tz.transition 2035, 4, :o2, 2061424800
-
1
tz.transition 2035, 9, :o1, 2074730400
-
1
tz.transition 2036, 4, :o2, 2092874400
-
1
tz.transition 2036, 9, :o1, 2106180000
-
1
tz.transition 2037, 4, :o2, 2124324000
-
1
tz.transition 2037, 9, :o1, 2137629600
-
1
tz.transition 2038, 4, :o2, 29586463, 12
-
1
tz.transition 2038, 9, :o1, 29588311, 12
-
1
tz.transition 2039, 4, :o2, 29590831, 12
-
1
tz.transition 2039, 9, :o1, 29592679, 12
-
1
tz.transition 2040, 4, :o2, 29595283, 12
-
1
tz.transition 2040, 9, :o1, 29597131, 12
-
1
tz.transition 2041, 4, :o2, 29599651, 12
-
1
tz.transition 2041, 9, :o1, 29601499, 12
-
1
tz.transition 2042, 4, :o2, 29604019, 12
-
1
tz.transition 2042, 9, :o1, 29605867, 12
-
1
tz.transition 2043, 4, :o2, 29608387, 12
-
1
tz.transition 2043, 9, :o1, 29610235, 12
-
1
tz.transition 2044, 4, :o2, 29612755, 12
-
1
tz.transition 2044, 9, :o1, 29614603, 12
-
1
tz.transition 2045, 4, :o2, 29617207, 12
-
1
tz.transition 2045, 9, :o1, 29618971, 12
-
1
tz.transition 2046, 4, :o2, 29621575, 12
-
1
tz.transition 2046, 9, :o1, 29623423, 12
-
1
tz.transition 2047, 4, :o2, 29625943, 12
-
1
tz.transition 2047, 9, :o1, 29627791, 12
-
1
tz.transition 2048, 4, :o2, 29630311, 12
-
1
tz.transition 2048, 9, :o1, 29632159, 12
-
1
tz.transition 2049, 4, :o2, 29634679, 12
-
1
tz.transition 2049, 9, :o1, 29636527, 12
-
1
tz.transition 2050, 4, :o2, 29639047, 12
-
1
tz.transition 2050, 9, :o1, 29640895, 12
-
end
-
end
-
end
-
end
-
end
-
1
module TZInfo
-
1
module Definitions
-
1
module Africa
-
1
module Harare
-
1
include TimezoneDefinition
-
-
1
timezone 'Africa/Harare' do |tz|
-
1
tz.offset :o0, 7452, 0, :LMT
-
1
tz.offset :o1, 7200, 0, :CAT
-
-
1
tz.transition 1903, 2, :o1, 1932939531, 800
-
end
-
end
-
end
-
end
-
end
-
1
module TZInfo
-
1
module Definitions
-
1
module Africa
-
1
module Johannesburg
-
1
include TimezoneDefinition
-
-
1
timezone 'Africa/Johannesburg' do |tz|
-
1
tz.offset :o0, 6720, 0, :LMT
-
1
tz.offset :o1, 5400, 0, :SAST
-
1
tz.offset :o2, 7200, 0, :SAST
-
1
tz.offset :o3, 7200, 3600, :SAST
-
-
1
tz.transition 1892, 2, :o1, 108546139, 45
-
1
tz.transition 1903, 2, :o2, 38658791, 16
-
1
tz.transition 1942, 9, :o3, 4861245, 2
-
1
tz.transition 1943, 3, :o2, 58339307, 24
-
1
tz.transition 1943, 9, :o3, 4861973, 2
-
1
tz.transition 1944, 3, :o2, 58348043, 24
-
end
-
end
-
end
-
end
-
end
-
1
module TZInfo
-
1
module Definitions
-
1
module Africa
-
1
module Monrovia
-
1
include TimezoneDefinition
-
-
1
timezone 'Africa/Monrovia' do |tz|
-
1
tz.offset :o0, -2588, 0, :LMT
-
1
tz.offset :o1, -2588, 0, :MMT
-
1
tz.offset :o2, -2670, 0, :LRT
-
1
tz.offset :o3, 0, 0, :GMT
-
-
1
tz.transition 1882, 1, :o1, 52022445047, 21600
-
1
tz.transition 1919, 3, :o2, 52315600247, 21600
-
1
tz.transition 1972, 5, :o3, 73529070
-
end
-
end
-
end
-
end
-
end
-
1
module TZInfo
-
1
module Definitions
-
1
module Africa
-
1
module Nairobi
-
1
include TimezoneDefinition
-
-
1
timezone 'Africa/Nairobi' do |tz|
-
1
tz.offset :o0, 8836, 0, :LMT
-
1
tz.offset :o1, 10800, 0, :EAT
-
1
tz.offset :o2, 9000, 0, :BEAT
-
1
tz.offset :o3, 9900, 0, :BEAUT
-
-
1
tz.transition 1928, 6, :o1, 52389253391, 21600
-
1
tz.transition 1929, 12, :o2, 19407819, 8
-
1
tz.transition 1939, 12, :o3, 116622211, 48
-
1
tz.transition 1959, 12, :o1, 233945701, 96
-
end
-
end
-
end
-
end
-
end
-
1
module TZInfo
-
1
module Definitions
-
1
module America
-
1
module Argentina
-
1
module Buenos_Aires
-
1
include TimezoneDefinition
-
-
1
timezone 'America/Argentina/Buenos_Aires' do |tz|
-
1
tz.offset :o0, -14028, 0, :LMT
-
1
tz.offset :o1, -15408, 0, :CMT
-
1
tz.offset :o2, -14400, 0, :ART
-
1
tz.offset :o3, -14400, 3600, :ARST
-
1
tz.offset :o4, -10800, 0, :ART
-
1
tz.offset :o5, -10800, 3600, :ARST
-
-
1
tz.transition 1894, 10, :o1, 17374555169, 7200
-
1
tz.transition 1920, 5, :o2, 1453467407, 600
-
1
tz.transition 1930, 12, :o3, 7278935, 3
-
1
tz.transition 1931, 4, :o2, 19411461, 8
-
1
tz.transition 1931, 10, :o3, 7279889, 3
-
1
tz.transition 1932, 3, :o2, 19414141, 8
-
1
tz.transition 1932, 11, :o3, 7281038, 3
-
1
tz.transition 1933, 3, :o2, 19417061, 8
-
1
tz.transition 1933, 11, :o3, 7282133, 3
-
1
tz.transition 1934, 3, :o2, 19419981, 8
-
1
tz.transition 1934, 11, :o3, 7283228, 3
-
1
tz.transition 1935, 3, :o2, 19422901, 8
-
1
tz.transition 1935, 11, :o3, 7284323, 3
-
1
tz.transition 1936, 3, :o2, 19425829, 8
-
1
tz.transition 1936, 11, :o3, 7285421, 3
-
1
tz.transition 1937, 3, :o2, 19428749, 8
-
1
tz.transition 1937, 11, :o3, 7286516, 3
-
1
tz.transition 1938, 3, :o2, 19431669, 8
-
1
tz.transition 1938, 11, :o3, 7287611, 3
-
1
tz.transition 1939, 3, :o2, 19434589, 8
-
1
tz.transition 1939, 11, :o3, 7288706, 3
-
1
tz.transition 1940, 3, :o2, 19437517, 8
-
1
tz.transition 1940, 7, :o3, 7289435, 3
-
1
tz.transition 1941, 6, :o2, 19441285, 8
-
1
tz.transition 1941, 10, :o3, 7290848, 3
-
1
tz.transition 1943, 8, :o2, 19447501, 8
-
1
tz.transition 1943, 10, :o3, 7293038, 3
-
1
tz.transition 1946, 3, :o2, 19455045, 8
-
1
tz.transition 1946, 10, :o3, 7296284, 3
-
1
tz.transition 1963, 10, :o2, 19506429, 8
-
1
tz.transition 1963, 12, :o3, 7315136, 3
-
1
tz.transition 1964, 3, :o2, 19507645, 8
-
1
tz.transition 1964, 10, :o3, 7316051, 3
-
1
tz.transition 1965, 3, :o2, 19510565, 8
-
1
tz.transition 1965, 10, :o3, 7317146, 3
-
1
tz.transition 1966, 3, :o2, 19513485, 8
-
1
tz.transition 1966, 10, :o3, 7318241, 3
-
1
tz.transition 1967, 4, :o2, 19516661, 8
-
1
tz.transition 1967, 10, :o3, 7319294, 3
-
1
tz.transition 1968, 4, :o2, 19519629, 8
-
1
tz.transition 1968, 10, :o3, 7320407, 3
-
1
tz.transition 1969, 4, :o2, 19522541, 8
-
1
tz.transition 1969, 10, :o4, 7321499, 3
-
1
tz.transition 1974, 1, :o5, 128142000
-
1
tz.transition 1974, 5, :o4, 136605600
-
1
tz.transition 1988, 12, :o5, 596948400
-
1
tz.transition 1989, 3, :o4, 605066400
-
1
tz.transition 1989, 10, :o5, 624423600
-
1
tz.transition 1990, 3, :o4, 636516000
-
1
tz.transition 1990, 10, :o5, 656478000
-
1
tz.transition 1991, 3, :o4, 667965600
-
1
tz.transition 1991, 10, :o5, 687927600
-
1
tz.transition 1992, 3, :o4, 699415200
-
1
tz.transition 1992, 10, :o5, 719377200
-
1
tz.transition 1993, 3, :o4, 731469600
-
1
tz.transition 1999, 10, :o3, 938919600
-
1
tz.transition 2000, 3, :o4, 952052400
-
1
tz.transition 2007, 12, :o5, 1198983600
-
1
tz.transition 2008, 3, :o4, 1205632800
-
1
tz.transition 2008, 10, :o5, 1224385200
-
1
tz.transition 2009, 3, :o4, 1237082400
-
end
-
end
-
end
-
end
-
end
-
end
-
1
module TZInfo
-
1
module Definitions
-
1
module America
-
1
module Bogota
-
1
include TimezoneDefinition
-
-
1
timezone 'America/Bogota' do |tz|
-
1
tz.offset :o0, -17780, 0, :LMT
-
1
tz.offset :o1, -17780, 0, :BMT
-
1
tz.offset :o2, -18000, 0, :COT
-
1
tz.offset :o3, -18000, 3600, :COST
-
-
1
tz.transition 1884, 3, :o1, 10407954409, 4320
-
1
tz.transition 1914, 11, :o2, 10456385929, 4320
-
1
tz.transition 1992, 5, :o3, 704869200
-
1
tz.transition 1993, 4, :o2, 733896000
-
end
-
end
-
end
-
end
-
end
-
1
module TZInfo
-
1
module Definitions
-
1
module America
-
1
module Caracas
-
1
include TimezoneDefinition
-
-
1
timezone 'America/Caracas' do |tz|
-
1
tz.offset :o0, -16064, 0, :LMT
-
1
tz.offset :o1, -16060, 0, :CMT
-
1
tz.offset :o2, -16200, 0, :VET
-
1
tz.offset :o3, -14400, 0, :VET
-
-
1
tz.transition 1890, 1, :o1, 1627673863, 675
-
1
tz.transition 1912, 2, :o2, 10452001043, 4320
-
1
tz.transition 1965, 1, :o3, 39020187, 16
-
1
tz.transition 2007, 12, :o2, 1197183600
-
end
-
end
-
end
-
end
-
end
-
1
module TZInfo
-
1
module Definitions
-
1
module America
-
1
module Chicago
-
1
include TimezoneDefinition
-
-
1
timezone 'America/Chicago' do |tz|
-
1
tz.offset :o0, -21036, 0, :LMT
-
1
tz.offset :o1, -21600, 0, :CST
-
1
tz.offset :o2, -21600, 3600, :CDT
-
1
tz.offset :o3, -18000, 0, :EST
-
1
tz.offset :o4, -21600, 3600, :CWT
-
1
tz.offset :o5, -21600, 3600, :CPT
-
-
1
tz.transition 1883, 11, :o1, 9636533, 4
-
1
tz.transition 1918, 3, :o2, 14530103, 6
-
1
tz.transition 1918, 10, :o1, 58125451, 24
-
1
tz.transition 1919, 3, :o2, 14532287, 6
-
1
tz.transition 1919, 10, :o1, 58134187, 24
-
1
tz.transition 1920, 6, :o2, 14534933, 6
-
1
tz.transition 1920, 10, :o1, 58143091, 24
-
1
tz.transition 1921, 3, :o2, 14536655, 6
-
1
tz.transition 1921, 10, :o1, 58151827, 24
-
1
tz.transition 1922, 4, :o2, 14539049, 6
-
1
tz.transition 1922, 9, :o1, 58159723, 24
-
1
tz.transition 1923, 4, :o2, 14541233, 6
-
1
tz.transition 1923, 9, :o1, 58168627, 24
-
1
tz.transition 1924, 4, :o2, 14543417, 6
-
1
tz.transition 1924, 9, :o1, 58177363, 24
-
1
tz.transition 1925, 4, :o2, 14545601, 6
-
1
tz.transition 1925, 9, :o1, 58186099, 24
-
1
tz.transition 1926, 4, :o2, 14547785, 6
-
1
tz.transition 1926, 9, :o1, 58194835, 24
-
1
tz.transition 1927, 4, :o2, 14549969, 6
-
1
tz.transition 1927, 9, :o1, 58203571, 24
-
1
tz.transition 1928, 4, :o2, 14552195, 6
-
1
tz.transition 1928, 9, :o1, 58212475, 24
-
1
tz.transition 1929, 4, :o2, 14554379, 6
-
1
tz.transition 1929, 9, :o1, 58221211, 24
-
1
tz.transition 1930, 4, :o2, 14556563, 6
-
1
tz.transition 1930, 9, :o1, 58229947, 24
-
1
tz.transition 1931, 4, :o2, 14558747, 6
-
1
tz.transition 1931, 9, :o1, 58238683, 24
-
1
tz.transition 1932, 4, :o2, 14560931, 6
-
1
tz.transition 1932, 9, :o1, 58247419, 24
-
1
tz.transition 1933, 4, :o2, 14563157, 6
-
1
tz.transition 1933, 9, :o1, 58256155, 24
-
1
tz.transition 1934, 4, :o2, 14565341, 6
-
1
tz.transition 1934, 9, :o1, 58265059, 24
-
1
tz.transition 1935, 4, :o2, 14567525, 6
-
1
tz.transition 1935, 9, :o1, 58273795, 24
-
1
tz.transition 1936, 3, :o3, 14569373, 6
-
1
tz.transition 1936, 11, :o1, 58283707, 24
-
1
tz.transition 1937, 4, :o2, 14571893, 6
-
1
tz.transition 1937, 9, :o1, 58291267, 24
-
1
tz.transition 1938, 4, :o2, 14574077, 6
-
1
tz.transition 1938, 9, :o1, 58300003, 24
-
1
tz.transition 1939, 4, :o2, 14576303, 6
-
1
tz.transition 1939, 9, :o1, 58308739, 24
-
1
tz.transition 1940, 4, :o2, 14578487, 6
-
1
tz.transition 1940, 9, :o1, 58317643, 24
-
1
tz.transition 1941, 4, :o2, 14580671, 6
-
1
tz.transition 1941, 9, :o1, 58326379, 24
-
1
tz.transition 1942, 2, :o4, 14582399, 6
-
1
tz.transition 1945, 8, :o5, 58360379, 24
-
1
tz.transition 1945, 9, :o1, 58361491, 24
-
1
tz.transition 1946, 4, :o2, 14591633, 6
-
1
tz.transition 1946, 9, :o1, 58370227, 24
-
1
tz.transition 1947, 4, :o2, 14593817, 6
-
1
tz.transition 1947, 9, :o1, 58378963, 24
-
1
tz.transition 1948, 4, :o2, 14596001, 6
-
1
tz.transition 1948, 9, :o1, 58387699, 24
-
1
tz.transition 1949, 4, :o2, 14598185, 6
-
1
tz.transition 1949, 9, :o1, 58396435, 24
-
1
tz.transition 1950, 4, :o2, 14600411, 6
-
1
tz.transition 1950, 9, :o1, 58405171, 24
-
1
tz.transition 1951, 4, :o2, 14602595, 6
-
1
tz.transition 1951, 9, :o1, 58414075, 24
-
1
tz.transition 1952, 4, :o2, 14604779, 6
-
1
tz.transition 1952, 9, :o1, 58422811, 24
-
1
tz.transition 1953, 4, :o2, 14606963, 6
-
1
tz.transition 1953, 9, :o1, 58431547, 24
-
1
tz.transition 1954, 4, :o2, 14609147, 6
-
1
tz.transition 1954, 9, :o1, 58440283, 24
-
1
tz.transition 1955, 4, :o2, 14611331, 6
-
1
tz.transition 1955, 10, :o1, 58449859, 24
-
1
tz.transition 1956, 4, :o2, 14613557, 6
-
1
tz.transition 1956, 10, :o1, 58458595, 24
-
1
tz.transition 1957, 4, :o2, 14615741, 6
-
1
tz.transition 1957, 10, :o1, 58467331, 24
-
1
tz.transition 1958, 4, :o2, 14617925, 6
-
1
tz.transition 1958, 10, :o1, 58476067, 24
-
1
tz.transition 1959, 4, :o2, 14620109, 6
-
1
tz.transition 1959, 10, :o1, 58484803, 24
-
1
tz.transition 1960, 4, :o2, 14622293, 6
-
1
tz.transition 1960, 10, :o1, 58493707, 24
-
1
tz.transition 1961, 4, :o2, 14624519, 6
-
1
tz.transition 1961, 10, :o1, 58502443, 24
-
1
tz.transition 1962, 4, :o2, 14626703, 6
-
1
tz.transition 1962, 10, :o1, 58511179, 24
-
1
tz.transition 1963, 4, :o2, 14628887, 6
-
1
tz.transition 1963, 10, :o1, 58519915, 24
-
1
tz.transition 1964, 4, :o2, 14631071, 6
-
1
tz.transition 1964, 10, :o1, 58528651, 24
-
1
tz.transition 1965, 4, :o2, 14633255, 6
-
1
tz.transition 1965, 10, :o1, 58537555, 24
-
1
tz.transition 1966, 4, :o2, 14635439, 6
-
1
tz.transition 1966, 10, :o1, 58546291, 24
-
1
tz.transition 1967, 4, :o2, 14637665, 6
-
1
tz.transition 1967, 10, :o1, 58555027, 24
-
1
tz.transition 1968, 4, :o2, 14639849, 6
-
1
tz.transition 1968, 10, :o1, 58563763, 24
-
1
tz.transition 1969, 4, :o2, 14642033, 6
-
1
tz.transition 1969, 10, :o1, 58572499, 24
-
1
tz.transition 1970, 4, :o2, 9964800
-
1
tz.transition 1970, 10, :o1, 25686000
-
1
tz.transition 1971, 4, :o2, 41414400
-
1
tz.transition 1971, 10, :o1, 57740400
-
1
tz.transition 1972, 4, :o2, 73468800
-
1
tz.transition 1972, 10, :o1, 89190000
-
1
tz.transition 1973, 4, :o2, 104918400
-
1
tz.transition 1973, 10, :o1, 120639600
-
1
tz.transition 1974, 1, :o2, 126691200
-
1
tz.transition 1974, 10, :o1, 152089200
-
1
tz.transition 1975, 2, :o2, 162374400
-
1
tz.transition 1975, 10, :o1, 183538800
-
1
tz.transition 1976, 4, :o2, 199267200
-
1
tz.transition 1976, 10, :o1, 215593200
-
1
tz.transition 1977, 4, :o2, 230716800
-
1
tz.transition 1977, 10, :o1, 247042800
-
1
tz.transition 1978, 4, :o2, 262771200
-
1
tz.transition 1978, 10, :o1, 278492400
-
1
tz.transition 1979, 4, :o2, 294220800
-
1
tz.transition 1979, 10, :o1, 309942000
-
1
tz.transition 1980, 4, :o2, 325670400
-
1
tz.transition 1980, 10, :o1, 341391600
-
1
tz.transition 1981, 4, :o2, 357120000
-
1
tz.transition 1981, 10, :o1, 372841200
-
1
tz.transition 1982, 4, :o2, 388569600
-
1
tz.transition 1982, 10, :o1, 404895600
-
1
tz.transition 1983, 4, :o2, 420019200
-
1
tz.transition 1983, 10, :o1, 436345200
-
1
tz.transition 1984, 4, :o2, 452073600
-
1
tz.transition 1984, 10, :o1, 467794800
-
1
tz.transition 1985, 4, :o2, 483523200
-
1
tz.transition 1985, 10, :o1, 499244400
-
1
tz.transition 1986, 4, :o2, 514972800
-
1
tz.transition 1986, 10, :o1, 530694000
-
1
tz.transition 1987, 4, :o2, 544608000
-
1
tz.transition 1987, 10, :o1, 562143600
-
1
tz.transition 1988, 4, :o2, 576057600
-
1
tz.transition 1988, 10, :o1, 594198000
-
1
tz.transition 1989, 4, :o2, 607507200
-
1
tz.transition 1989, 10, :o1, 625647600
-
1
tz.transition 1990, 4, :o2, 638956800
-
1
tz.transition 1990, 10, :o1, 657097200
-
1
tz.transition 1991, 4, :o2, 671011200
-
1
tz.transition 1991, 10, :o1, 688546800
-
1
tz.transition 1992, 4, :o2, 702460800
-
1
tz.transition 1992, 10, :o1, 719996400
-
1
tz.transition 1993, 4, :o2, 733910400
-
1
tz.transition 1993, 10, :o1, 752050800
-
1
tz.transition 1994, 4, :o2, 765360000
-
1
tz.transition 1994, 10, :o1, 783500400
-
1
tz.transition 1995, 4, :o2, 796809600
-
1
tz.transition 1995, 10, :o1, 814950000
-
1
tz.transition 1996, 4, :o2, 828864000
-
1
tz.transition 1996, 10, :o1, 846399600
-
1
tz.transition 1997, 4, :o2, 860313600
-
1
tz.transition 1997, 10, :o1, 877849200
-
1
tz.transition 1998, 4, :o2, 891763200
-
1
tz.transition 1998, 10, :o1, 909298800
-
1
tz.transition 1999, 4, :o2, 923212800
-
1
tz.transition 1999, 10, :o1, 941353200
-
1
tz.transition 2000, 4, :o2, 954662400
-
1
tz.transition 2000, 10, :o1, 972802800
-
1
tz.transition 2001, 4, :o2, 986112000
-
1
tz.transition 2001, 10, :o1, 1004252400
-
1
tz.transition 2002, 4, :o2, 1018166400
-
1
tz.transition 2002, 10, :o1, 1035702000
-
1
tz.transition 2003, 4, :o2, 1049616000
-
1
tz.transition 2003, 10, :o1, 1067151600
-
1
tz.transition 2004, 4, :o2, 1081065600
-
1
tz.transition 2004, 10, :o1, 1099206000
-
1
tz.transition 2005, 4, :o2, 1112515200
-
1
tz.transition 2005, 10, :o1, 1130655600
-
1
tz.transition 2006, 4, :o2, 1143964800
-
1
tz.transition 2006, 10, :o1, 1162105200
-
1
tz.transition 2007, 3, :o2, 1173600000
-
1
tz.transition 2007, 11, :o1, 1194159600
-
1
tz.transition 2008, 3, :o2, 1205049600
-
1
tz.transition 2008, 11, :o1, 1225609200
-
1
tz.transition 2009, 3, :o2, 1236499200
-
1
tz.transition 2009, 11, :o1, 1257058800
-
1
tz.transition 2010, 3, :o2, 1268553600
-
1
tz.transition 2010, 11, :o1, 1289113200
-
1
tz.transition 2011, 3, :o2, 1300003200
-
1
tz.transition 2011, 11, :o1, 1320562800
-
1
tz.transition 2012, 3, :o2, 1331452800
-
1
tz.transition 2012, 11, :o1, 1352012400
-
1
tz.transition 2013, 3, :o2, 1362902400
-
1
tz.transition 2013, 11, :o1, 1383462000
-
1
tz.transition 2014, 3, :o2, 1394352000
-
1
tz.transition 2014, 11, :o1, 1414911600
-
1
tz.transition 2015, 3, :o2, 1425801600
-
1
tz.transition 2015, 11, :o1, 1446361200
-
1
tz.transition 2016, 3, :o2, 1457856000
-
1
tz.transition 2016, 11, :o1, 1478415600
-
1
tz.transition 2017, 3, :o2, 1489305600
-
1
tz.transition 2017, 11, :o1, 1509865200
-
1
tz.transition 2018, 3, :o2, 1520755200
-
1
tz.transition 2018, 11, :o1, 1541314800
-
1
tz.transition 2019, 3, :o2, 1552204800
-
1
tz.transition 2019, 11, :o1, 1572764400
-
1
tz.transition 2020, 3, :o2, 1583654400
-
1
tz.transition 2020, 11, :o1, 1604214000
-
1
tz.transition 2021, 3, :o2, 1615708800
-
1
tz.transition 2021, 11, :o1, 1636268400
-
1
tz.transition 2022, 3, :o2, 1647158400
-
1
tz.transition 2022, 11, :o1, 1667718000
-
1
tz.transition 2023, 3, :o2, 1678608000
-
1
tz.transition 2023, 11, :o1, 1699167600
-
1
tz.transition 2024, 3, :o2, 1710057600
-
1
tz.transition 2024, 11, :o1, 1730617200
-
1
tz.transition 2025, 3, :o2, 1741507200
-
1
tz.transition 2025, 11, :o1, 1762066800
-
1
tz.transition 2026, 3, :o2, 1772956800
-
1
tz.transition 2026, 11, :o1, 1793516400
-
1
tz.transition 2027, 3, :o2, 1805011200
-
1
tz.transition 2027, 11, :o1, 1825570800
-
1
tz.transition 2028, 3, :o2, 1836460800
-
1
tz.transition 2028, 11, :o1, 1857020400
-
1
tz.transition 2029, 3, :o2, 1867910400
-
1
tz.transition 2029, 11, :o1, 1888470000
-
1
tz.transition 2030, 3, :o2, 1899360000
-
1
tz.transition 2030, 11, :o1, 1919919600
-
1
tz.transition 2031, 3, :o2, 1930809600
-
1
tz.transition 2031, 11, :o1, 1951369200
-
1
tz.transition 2032, 3, :o2, 1962864000
-
1
tz.transition 2032, 11, :o1, 1983423600
-
1
tz.transition 2033, 3, :o2, 1994313600
-
1
tz.transition 2033, 11, :o1, 2014873200
-
1
tz.transition 2034, 3, :o2, 2025763200
-
1
tz.transition 2034, 11, :o1, 2046322800
-
1
tz.transition 2035, 3, :o2, 2057212800
-
1
tz.transition 2035, 11, :o1, 2077772400
-
1
tz.transition 2036, 3, :o2, 2088662400
-
1
tz.transition 2036, 11, :o1, 2109222000
-
1
tz.transition 2037, 3, :o2, 2120112000
-
1
tz.transition 2037, 11, :o1, 2140671600
-
1
tz.transition 2038, 3, :o2, 14792981, 6
-
1
tz.transition 2038, 11, :o1, 59177635, 24
-
1
tz.transition 2039, 3, :o2, 14795165, 6
-
1
tz.transition 2039, 11, :o1, 59186371, 24
-
1
tz.transition 2040, 3, :o2, 14797349, 6
-
1
tz.transition 2040, 11, :o1, 59195107, 24
-
1
tz.transition 2041, 3, :o2, 14799533, 6
-
1
tz.transition 2041, 11, :o1, 59203843, 24
-
1
tz.transition 2042, 3, :o2, 14801717, 6
-
1
tz.transition 2042, 11, :o1, 59212579, 24
-
1
tz.transition 2043, 3, :o2, 14803901, 6
-
1
tz.transition 2043, 11, :o1, 59221315, 24
-
1
tz.transition 2044, 3, :o2, 14806127, 6
-
1
tz.transition 2044, 11, :o1, 59230219, 24
-
1
tz.transition 2045, 3, :o2, 14808311, 6
-
1
tz.transition 2045, 11, :o1, 59238955, 24
-
1
tz.transition 2046, 3, :o2, 14810495, 6
-
1
tz.transition 2046, 11, :o1, 59247691, 24
-
1
tz.transition 2047, 3, :o2, 14812679, 6
-
1
tz.transition 2047, 11, :o1, 59256427, 24
-
1
tz.transition 2048, 3, :o2, 14814863, 6
-
1
tz.transition 2048, 11, :o1, 59265163, 24
-
1
tz.transition 2049, 3, :o2, 14817089, 6
-
1
tz.transition 2049, 11, :o1, 59274067, 24
-
1
tz.transition 2050, 3, :o2, 14819273, 6
-
1
tz.transition 2050, 11, :o1, 59282803, 24
-
end
-
end
-
end
-
end
-
end
-
1
module TZInfo
-
1
module Definitions
-
1
module America
-
1
module Chihuahua
-
1
include TimezoneDefinition
-
-
1
timezone 'America/Chihuahua' do |tz|
-
1
tz.offset :o0, -25460, 0, :LMT
-
1
tz.offset :o1, -25200, 0, :MST
-
1
tz.offset :o2, -21600, 0, :CST
-
1
tz.offset :o3, -21600, 3600, :CDT
-
1
tz.offset :o4, -25200, 3600, :MDT
-
-
1
tz.transition 1922, 1, :o1, 58153339, 24
-
1
tz.transition 1927, 6, :o2, 9700171, 4
-
1
tz.transition 1930, 11, :o1, 9705183, 4
-
1
tz.transition 1931, 5, :o2, 9705855, 4
-
1
tz.transition 1931, 10, :o1, 9706463, 4
-
1
tz.transition 1932, 4, :o2, 58243171, 24
-
1
tz.transition 1996, 4, :o3, 828864000
-
1
tz.transition 1996, 10, :o2, 846399600
-
1
tz.transition 1997, 4, :o3, 860313600
-
1
tz.transition 1997, 10, :o2, 877849200
-
1
tz.transition 1998, 4, :o4, 891766800
-
1
tz.transition 1998, 10, :o1, 909302400
-
1
tz.transition 1999, 4, :o4, 923216400
-
1
tz.transition 1999, 10, :o1, 941356800
-
1
tz.transition 2000, 4, :o4, 954666000
-
1
tz.transition 2000, 10, :o1, 972806400
-
1
tz.transition 2001, 5, :o4, 989139600
-
1
tz.transition 2001, 9, :o1, 1001836800
-
1
tz.transition 2002, 4, :o4, 1018170000
-
1
tz.transition 2002, 10, :o1, 1035705600
-
1
tz.transition 2003, 4, :o4, 1049619600
-
1
tz.transition 2003, 10, :o1, 1067155200
-
1
tz.transition 2004, 4, :o4, 1081069200
-
1
tz.transition 2004, 10, :o1, 1099209600
-
1
tz.transition 2005, 4, :o4, 1112518800
-
1
tz.transition 2005, 10, :o1, 1130659200
-
1
tz.transition 2006, 4, :o4, 1143968400
-
1
tz.transition 2006, 10, :o1, 1162108800
-
1
tz.transition 2007, 4, :o4, 1175418000
-
1
tz.transition 2007, 10, :o1, 1193558400
-
1
tz.transition 2008, 4, :o4, 1207472400
-
1
tz.transition 2008, 10, :o1, 1225008000
-
1
tz.transition 2009, 4, :o4, 1238922000
-
1
tz.transition 2009, 10, :o1, 1256457600
-
1
tz.transition 2010, 4, :o4, 1270371600
-
1
tz.transition 2010, 10, :o1, 1288512000
-
1
tz.transition 2011, 4, :o4, 1301821200
-
1
tz.transition 2011, 10, :o1, 1319961600
-
1
tz.transition 2012, 4, :o4, 1333270800
-
1
tz.transition 2012, 10, :o1, 1351411200
-
1
tz.transition 2013, 4, :o4, 1365325200
-
1
tz.transition 2013, 10, :o1, 1382860800
-
1
tz.transition 2014, 4, :o4, 1396774800
-
1
tz.transition 2014, 10, :o1, 1414310400
-
1
tz.transition 2015, 4, :o4, 1428224400
-
1
tz.transition 2015, 10, :o1, 1445760000
-
1
tz.transition 2016, 4, :o4, 1459674000
-
1
tz.transition 2016, 10, :o1, 1477814400
-
1
tz.transition 2017, 4, :o4, 1491123600
-
1
tz.transition 2017, 10, :o1, 1509264000
-
1
tz.transition 2018, 4, :o4, 1522573200
-
1
tz.transition 2018, 10, :o1, 1540713600
-
1
tz.transition 2019, 4, :o4, 1554627600
-
1
tz.transition 2019, 10, :o1, 1572163200
-
1
tz.transition 2020, 4, :o4, 1586077200
-
1
tz.transition 2020, 10, :o1, 1603612800
-
1
tz.transition 2021, 4, :o4, 1617526800
-
1
tz.transition 2021, 10, :o1, 1635667200
-
1
tz.transition 2022, 4, :o4, 1648976400
-
1
tz.transition 2022, 10, :o1, 1667116800
-
1
tz.transition 2023, 4, :o4, 1680426000
-
1
tz.transition 2023, 10, :o1, 1698566400
-
1
tz.transition 2024, 4, :o4, 1712480400
-
1
tz.transition 2024, 10, :o1, 1730016000
-
1
tz.transition 2025, 4, :o4, 1743930000
-
1
tz.transition 2025, 10, :o1, 1761465600
-
1
tz.transition 2026, 4, :o4, 1775379600
-
1
tz.transition 2026, 10, :o1, 1792915200
-
1
tz.transition 2027, 4, :o4, 1806829200
-
1
tz.transition 2027, 10, :o1, 1824969600
-
1
tz.transition 2028, 4, :o4, 1838278800
-
1
tz.transition 2028, 10, :o1, 1856419200
-
1
tz.transition 2029, 4, :o4, 1869728400
-
1
tz.transition 2029, 10, :o1, 1887868800
-
1
tz.transition 2030, 4, :o4, 1901782800
-
1
tz.transition 2030, 10, :o1, 1919318400
-
1
tz.transition 2031, 4, :o4, 1933232400
-
1
tz.transition 2031, 10, :o1, 1950768000
-
1
tz.transition 2032, 4, :o4, 1964682000
-
1
tz.transition 2032, 10, :o1, 1982822400
-
1
tz.transition 2033, 4, :o4, 1996131600
-
1
tz.transition 2033, 10, :o1, 2014272000
-
1
tz.transition 2034, 4, :o4, 2027581200
-
1
tz.transition 2034, 10, :o1, 2045721600
-
1
tz.transition 2035, 4, :o4, 2059030800
-
1
tz.transition 2035, 10, :o1, 2077171200
-
1
tz.transition 2036, 4, :o4, 2091085200
-
1
tz.transition 2036, 10, :o1, 2108620800
-
1
tz.transition 2037, 4, :o4, 2122534800
-
1
tz.transition 2037, 10, :o1, 2140070400
-
1
tz.transition 2038, 4, :o4, 19724143, 8
-
1
tz.transition 2038, 10, :o1, 14794367, 6
-
1
tz.transition 2039, 4, :o4, 19727055, 8
-
1
tz.transition 2039, 10, :o1, 14796551, 6
-
1
tz.transition 2040, 4, :o4, 19729967, 8
-
1
tz.transition 2040, 10, :o1, 14798735, 6
-
1
tz.transition 2041, 4, :o4, 19732935, 8
-
1
tz.transition 2041, 10, :o1, 14800919, 6
-
1
tz.transition 2042, 4, :o4, 19735847, 8
-
1
tz.transition 2042, 10, :o1, 14803103, 6
-
1
tz.transition 2043, 4, :o4, 19738759, 8
-
1
tz.transition 2043, 10, :o1, 14805287, 6
-
1
tz.transition 2044, 4, :o4, 19741671, 8
-
1
tz.transition 2044, 10, :o1, 14807513, 6
-
1
tz.transition 2045, 4, :o4, 19744583, 8
-
1
tz.transition 2045, 10, :o1, 14809697, 6
-
1
tz.transition 2046, 4, :o4, 19747495, 8
-
1
tz.transition 2046, 10, :o1, 14811881, 6
-
1
tz.transition 2047, 4, :o4, 19750463, 8
-
1
tz.transition 2047, 10, :o1, 14814065, 6
-
1
tz.transition 2048, 4, :o4, 19753375, 8
-
1
tz.transition 2048, 10, :o1, 14816249, 6
-
1
tz.transition 2049, 4, :o4, 19756287, 8
-
1
tz.transition 2049, 10, :o1, 14818475, 6
-
1
tz.transition 2050, 4, :o4, 19759199, 8
-
1
tz.transition 2050, 10, :o1, 14820659, 6
-
end
-
end
-
end
-
end
-
end
-
1
module TZInfo
-
1
module Definitions
-
1
module America
-
1
module Denver
-
1
include TimezoneDefinition
-
-
1
timezone 'America/Denver' do |tz|
-
1
tz.offset :o0, -25196, 0, :LMT
-
1
tz.offset :o1, -25200, 0, :MST
-
1
tz.offset :o2, -25200, 3600, :MDT
-
1
tz.offset :o3, -25200, 3600, :MWT
-
1
tz.offset :o4, -25200, 3600, :MPT
-
-
1
tz.transition 1883, 11, :o1, 57819199, 24
-
1
tz.transition 1918, 3, :o2, 19373471, 8
-
1
tz.transition 1918, 10, :o1, 14531363, 6
-
1
tz.transition 1919, 3, :o2, 19376383, 8
-
1
tz.transition 1919, 10, :o1, 14533547, 6
-
1
tz.transition 1920, 3, :o2, 19379295, 8
-
1
tz.transition 1920, 10, :o1, 14535773, 6
-
1
tz.transition 1921, 3, :o2, 19382207, 8
-
1
tz.transition 1921, 5, :o1, 14536991, 6
-
1
tz.transition 1942, 2, :o3, 19443199, 8
-
1
tz.transition 1945, 8, :o4, 58360379, 24
-
1
tz.transition 1945, 9, :o1, 14590373, 6
-
1
tz.transition 1965, 4, :o2, 19511007, 8
-
1
tz.transition 1965, 10, :o1, 14634389, 6
-
1
tz.transition 1966, 4, :o2, 19513919, 8
-
1
tz.transition 1966, 10, :o1, 14636573, 6
-
1
tz.transition 1967, 4, :o2, 19516887, 8
-
1
tz.transition 1967, 10, :o1, 14638757, 6
-
1
tz.transition 1968, 4, :o2, 19519799, 8
-
1
tz.transition 1968, 10, :o1, 14640941, 6
-
1
tz.transition 1969, 4, :o2, 19522711, 8
-
1
tz.transition 1969, 10, :o1, 14643125, 6
-
1
tz.transition 1970, 4, :o2, 9968400
-
1
tz.transition 1970, 10, :o1, 25689600
-
1
tz.transition 1971, 4, :o2, 41418000
-
1
tz.transition 1971, 10, :o1, 57744000
-
1
tz.transition 1972, 4, :o2, 73472400
-
1
tz.transition 1972, 10, :o1, 89193600
-
1
tz.transition 1973, 4, :o2, 104922000
-
1
tz.transition 1973, 10, :o1, 120643200
-
1
tz.transition 1974, 1, :o2, 126694800
-
1
tz.transition 1974, 10, :o1, 152092800
-
1
tz.transition 1975, 2, :o2, 162378000
-
1
tz.transition 1975, 10, :o1, 183542400
-
1
tz.transition 1976, 4, :o2, 199270800
-
1
tz.transition 1976, 10, :o1, 215596800
-
1
tz.transition 1977, 4, :o2, 230720400
-
1
tz.transition 1977, 10, :o1, 247046400
-
1
tz.transition 1978, 4, :o2, 262774800
-
1
tz.transition 1978, 10, :o1, 278496000
-
1
tz.transition 1979, 4, :o2, 294224400
-
1
tz.transition 1979, 10, :o1, 309945600
-
1
tz.transition 1980, 4, :o2, 325674000
-
1
tz.transition 1980, 10, :o1, 341395200
-
1
tz.transition 1981, 4, :o2, 357123600
-
1
tz.transition 1981, 10, :o1, 372844800
-
1
tz.transition 1982, 4, :o2, 388573200
-
1
tz.transition 1982, 10, :o1, 404899200
-
1
tz.transition 1983, 4, :o2, 420022800
-
1
tz.transition 1983, 10, :o1, 436348800
-
1
tz.transition 1984, 4, :o2, 452077200
-
1
tz.transition 1984, 10, :o1, 467798400
-
1
tz.transition 1985, 4, :o2, 483526800
-
1
tz.transition 1985, 10, :o1, 499248000
-
1
tz.transition 1986, 4, :o2, 514976400
-
1
tz.transition 1986, 10, :o1, 530697600
-
1
tz.transition 1987, 4, :o2, 544611600
-
1
tz.transition 1987, 10, :o1, 562147200
-
1
tz.transition 1988, 4, :o2, 576061200
-
1
tz.transition 1988, 10, :o1, 594201600
-
1
tz.transition 1989, 4, :o2, 607510800
-
1
tz.transition 1989, 10, :o1, 625651200
-
1
tz.transition 1990, 4, :o2, 638960400
-
1
tz.transition 1990, 10, :o1, 657100800
-
1
tz.transition 1991, 4, :o2, 671014800
-
1
tz.transition 1991, 10, :o1, 688550400
-
1
tz.transition 1992, 4, :o2, 702464400
-
1
tz.transition 1992, 10, :o1, 720000000
-
1
tz.transition 1993, 4, :o2, 733914000
-
1
tz.transition 1993, 10, :o1, 752054400
-
1
tz.transition 1994, 4, :o2, 765363600
-
1
tz.transition 1994, 10, :o1, 783504000
-
1
tz.transition 1995, 4, :o2, 796813200
-
1
tz.transition 1995, 10, :o1, 814953600
-
1
tz.transition 1996, 4, :o2, 828867600
-
1
tz.transition 1996, 10, :o1, 846403200
-
1
tz.transition 1997, 4, :o2, 860317200
-
1
tz.transition 1997, 10, :o1, 877852800
-
1
tz.transition 1998, 4, :o2, 891766800
-
1
tz.transition 1998, 10, :o1, 909302400
-
1
tz.transition 1999, 4, :o2, 923216400
-
1
tz.transition 1999, 10, :o1, 941356800
-
1
tz.transition 2000, 4, :o2, 954666000
-
1
tz.transition 2000, 10, :o1, 972806400
-
1
tz.transition 2001, 4, :o2, 986115600
-
1
tz.transition 2001, 10, :o1, 1004256000
-
1
tz.transition 2002, 4, :o2, 1018170000
-
1
tz.transition 2002, 10, :o1, 1035705600
-
1
tz.transition 2003, 4, :o2, 1049619600
-
1
tz.transition 2003, 10, :o1, 1067155200
-
1
tz.transition 2004, 4, :o2, 1081069200
-
1
tz.transition 2004, 10, :o1, 1099209600
-
1
tz.transition 2005, 4, :o2, 1112518800
-
1
tz.transition 2005, 10, :o1, 1130659200
-
1
tz.transition 2006, 4, :o2, 1143968400
-
1
tz.transition 2006, 10, :o1, 1162108800
-
1
tz.transition 2007, 3, :o2, 1173603600
-
1
tz.transition 2007, 11, :o1, 1194163200
-
1
tz.transition 2008, 3, :o2, 1205053200
-
1
tz.transition 2008, 11, :o1, 1225612800
-
1
tz.transition 2009, 3, :o2, 1236502800
-
1
tz.transition 2009, 11, :o1, 1257062400
-
1
tz.transition 2010, 3, :o2, 1268557200
-
1
tz.transition 2010, 11, :o1, 1289116800
-
1
tz.transition 2011, 3, :o2, 1300006800
-
1
tz.transition 2011, 11, :o1, 1320566400
-
1
tz.transition 2012, 3, :o2, 1331456400
-
1
tz.transition 2012, 11, :o1, 1352016000
-
1
tz.transition 2013, 3, :o2, 1362906000
-
1
tz.transition 2013, 11, :o1, 1383465600
-
1
tz.transition 2014, 3, :o2, 1394355600
-
1
tz.transition 2014, 11, :o1, 1414915200
-
1
tz.transition 2015, 3, :o2, 1425805200
-
1
tz.transition 2015, 11, :o1, 1446364800
-
1
tz.transition 2016, 3, :o2, 1457859600
-
1
tz.transition 2016, 11, :o1, 1478419200
-
1
tz.transition 2017, 3, :o2, 1489309200
-
1
tz.transition 2017, 11, :o1, 1509868800
-
1
tz.transition 2018, 3, :o2, 1520758800
-
1
tz.transition 2018, 11, :o1, 1541318400
-
1
tz.transition 2019, 3, :o2, 1552208400
-
1
tz.transition 2019, 11, :o1, 1572768000
-
1
tz.transition 2020, 3, :o2, 1583658000
-
1
tz.transition 2020, 11, :o1, 1604217600
-
1
tz.transition 2021, 3, :o2, 1615712400
-
1
tz.transition 2021, 11, :o1, 1636272000
-
1
tz.transition 2022, 3, :o2, 1647162000
-
1
tz.transition 2022, 11, :o1, 1667721600
-
1
tz.transition 2023, 3, :o2, 1678611600
-
1
tz.transition 2023, 11, :o1, 1699171200
-
1
tz.transition 2024, 3, :o2, 1710061200
-
1
tz.transition 2024, 11, :o1, 1730620800
-
1
tz.transition 2025, 3, :o2, 1741510800
-
1
tz.transition 2025, 11, :o1, 1762070400
-
1
tz.transition 2026, 3, :o2, 1772960400
-
1
tz.transition 2026, 11, :o1, 1793520000
-
1
tz.transition 2027, 3, :o2, 1805014800
-
1
tz.transition 2027, 11, :o1, 1825574400
-
1
tz.transition 2028, 3, :o2, 1836464400
-
1
tz.transition 2028, 11, :o1, 1857024000
-
1
tz.transition 2029, 3, :o2, 1867914000
-
1
tz.transition 2029, 11, :o1, 1888473600
-
1
tz.transition 2030, 3, :o2, 1899363600
-
1
tz.transition 2030, 11, :o1, 1919923200
-
1
tz.transition 2031, 3, :o2, 1930813200
-
1
tz.transition 2031, 11, :o1, 1951372800
-
1
tz.transition 2032, 3, :o2, 1962867600
-
1
tz.transition 2032, 11, :o1, 1983427200
-
1
tz.transition 2033, 3, :o2, 1994317200
-
1
tz.transition 2033, 11, :o1, 2014876800
-
1
tz.transition 2034, 3, :o2, 2025766800
-
1
tz.transition 2034, 11, :o1, 2046326400
-
1
tz.transition 2035, 3, :o2, 2057216400
-
1
tz.transition 2035, 11, :o1, 2077776000
-
1
tz.transition 2036, 3, :o2, 2088666000
-
1
tz.transition 2036, 11, :o1, 2109225600
-
1
tz.transition 2037, 3, :o2, 2120115600
-
1
tz.transition 2037, 11, :o1, 2140675200
-
1
tz.transition 2038, 3, :o2, 19723975, 8
-
1
tz.transition 2038, 11, :o1, 14794409, 6
-
1
tz.transition 2039, 3, :o2, 19726887, 8
-
1
tz.transition 2039, 11, :o1, 14796593, 6
-
1
tz.transition 2040, 3, :o2, 19729799, 8
-
1
tz.transition 2040, 11, :o1, 14798777, 6
-
1
tz.transition 2041, 3, :o2, 19732711, 8
-
1
tz.transition 2041, 11, :o1, 14800961, 6
-
1
tz.transition 2042, 3, :o2, 19735623, 8
-
1
tz.transition 2042, 11, :o1, 14803145, 6
-
1
tz.transition 2043, 3, :o2, 19738535, 8
-
1
tz.transition 2043, 11, :o1, 14805329, 6
-
1
tz.transition 2044, 3, :o2, 19741503, 8
-
1
tz.transition 2044, 11, :o1, 14807555, 6
-
1
tz.transition 2045, 3, :o2, 19744415, 8
-
1
tz.transition 2045, 11, :o1, 14809739, 6
-
1
tz.transition 2046, 3, :o2, 19747327, 8
-
1
tz.transition 2046, 11, :o1, 14811923, 6
-
1
tz.transition 2047, 3, :o2, 19750239, 8
-
1
tz.transition 2047, 11, :o1, 14814107, 6
-
1
tz.transition 2048, 3, :o2, 19753151, 8
-
1
tz.transition 2048, 11, :o1, 14816291, 6
-
1
tz.transition 2049, 3, :o2, 19756119, 8
-
1
tz.transition 2049, 11, :o1, 14818517, 6
-
1
tz.transition 2050, 3, :o2, 19759031, 8
-
1
tz.transition 2050, 11, :o1, 14820701, 6
-
end
-
end
-
end
-
end
-
end
-
1
module TZInfo
-
1
module Definitions
-
1
module America
-
1
module Godthab
-
1
include TimezoneDefinition
-
-
1
timezone 'America/Godthab' do |tz|
-
1
tz.offset :o0, -12416, 0, :LMT
-
1
tz.offset :o1, -10800, 0, :WGT
-
1
tz.offset :o2, -10800, 3600, :WGST
-
-
1
tz.transition 1916, 7, :o1, 3268448069, 1350
-
1
tz.transition 1980, 4, :o2, 323845200
-
1
tz.transition 1980, 9, :o1, 338950800
-
1
tz.transition 1981, 3, :o2, 354675600
-
1
tz.transition 1981, 9, :o1, 370400400
-
1
tz.transition 1982, 3, :o2, 386125200
-
1
tz.transition 1982, 9, :o1, 401850000
-
1
tz.transition 1983, 3, :o2, 417574800
-
1
tz.transition 1983, 9, :o1, 433299600
-
1
tz.transition 1984, 3, :o2, 449024400
-
1
tz.transition 1984, 9, :o1, 465354000
-
1
tz.transition 1985, 3, :o2, 481078800
-
1
tz.transition 1985, 9, :o1, 496803600
-
1
tz.transition 1986, 3, :o2, 512528400
-
1
tz.transition 1986, 9, :o1, 528253200
-
1
tz.transition 1987, 3, :o2, 543978000
-
1
tz.transition 1987, 9, :o1, 559702800
-
1
tz.transition 1988, 3, :o2, 575427600
-
1
tz.transition 1988, 9, :o1, 591152400
-
1
tz.transition 1989, 3, :o2, 606877200
-
1
tz.transition 1989, 9, :o1, 622602000
-
1
tz.transition 1990, 3, :o2, 638326800
-
1
tz.transition 1990, 9, :o1, 654656400
-
1
tz.transition 1991, 3, :o2, 670381200
-
1
tz.transition 1991, 9, :o1, 686106000
-
1
tz.transition 1992, 3, :o2, 701830800
-
1
tz.transition 1992, 9, :o1, 717555600
-
1
tz.transition 1993, 3, :o2, 733280400
-
1
tz.transition 1993, 9, :o1, 749005200
-
1
tz.transition 1994, 3, :o2, 764730000
-
1
tz.transition 1994, 9, :o1, 780454800
-
1
tz.transition 1995, 3, :o2, 796179600
-
1
tz.transition 1995, 9, :o1, 811904400
-
1
tz.transition 1996, 3, :o2, 828234000
-
1
tz.transition 1996, 10, :o1, 846378000
-
1
tz.transition 1997, 3, :o2, 859683600
-
1
tz.transition 1997, 10, :o1, 877827600
-
1
tz.transition 1998, 3, :o2, 891133200
-
1
tz.transition 1998, 10, :o1, 909277200
-
1
tz.transition 1999, 3, :o2, 922582800
-
1
tz.transition 1999, 10, :o1, 941331600
-
1
tz.transition 2000, 3, :o2, 954032400
-
1
tz.transition 2000, 10, :o1, 972781200
-
1
tz.transition 2001, 3, :o2, 985482000
-
1
tz.transition 2001, 10, :o1, 1004230800
-
1
tz.transition 2002, 3, :o2, 1017536400
-
1
tz.transition 2002, 10, :o1, 1035680400
-
1
tz.transition 2003, 3, :o2, 1048986000
-
1
tz.transition 2003, 10, :o1, 1067130000
-
1
tz.transition 2004, 3, :o2, 1080435600
-
1
tz.transition 2004, 10, :o1, 1099184400
-
1
tz.transition 2005, 3, :o2, 1111885200
-
1
tz.transition 2005, 10, :o1, 1130634000
-
1
tz.transition 2006, 3, :o2, 1143334800
-
1
tz.transition 2006, 10, :o1, 1162083600
-
1
tz.transition 2007, 3, :o2, 1174784400
-
1
tz.transition 2007, 10, :o1, 1193533200
-
1
tz.transition 2008, 3, :o2, 1206838800
-
1
tz.transition 2008, 10, :o1, 1224982800
-
1
tz.transition 2009, 3, :o2, 1238288400
-
1
tz.transition 2009, 10, :o1, 1256432400
-
1
tz.transition 2010, 3, :o2, 1269738000
-
1
tz.transition 2010, 10, :o1, 1288486800
-
1
tz.transition 2011, 3, :o2, 1301187600
-
1
tz.transition 2011, 10, :o1, 1319936400
-
1
tz.transition 2012, 3, :o2, 1332637200
-
1
tz.transition 2012, 10, :o1, 1351386000
-
1
tz.transition 2013, 3, :o2, 1364691600
-
1
tz.transition 2013, 10, :o1, 1382835600
-
1
tz.transition 2014, 3, :o2, 1396141200
-
1
tz.transition 2014, 10, :o1, 1414285200
-
1
tz.transition 2015, 3, :o2, 1427590800
-
1
tz.transition 2015, 10, :o1, 1445734800
-
1
tz.transition 2016, 3, :o2, 1459040400
-
1
tz.transition 2016, 10, :o1, 1477789200
-
1
tz.transition 2017, 3, :o2, 1490490000
-
1
tz.transition 2017, 10, :o1, 1509238800
-
1
tz.transition 2018, 3, :o2, 1521939600
-
1
tz.transition 2018, 10, :o1, 1540688400
-
1
tz.transition 2019, 3, :o2, 1553994000
-
1
tz.transition 2019, 10, :o1, 1572138000
-
1
tz.transition 2020, 3, :o2, 1585443600
-
1
tz.transition 2020, 10, :o1, 1603587600
-
1
tz.transition 2021, 3, :o2, 1616893200
-
1
tz.transition 2021, 10, :o1, 1635642000
-
1
tz.transition 2022, 3, :o2, 1648342800
-
1
tz.transition 2022, 10, :o1, 1667091600
-
1
tz.transition 2023, 3, :o2, 1679792400
-
1
tz.transition 2023, 10, :o1, 1698541200
-
1
tz.transition 2024, 3, :o2, 1711846800
-
1
tz.transition 2024, 10, :o1, 1729990800
-
1
tz.transition 2025, 3, :o2, 1743296400
-
1
tz.transition 2025, 10, :o1, 1761440400
-
1
tz.transition 2026, 3, :o2, 1774746000
-
1
tz.transition 2026, 10, :o1, 1792890000
-
1
tz.transition 2027, 3, :o2, 1806195600
-
1
tz.transition 2027, 10, :o1, 1824944400
-
1
tz.transition 2028, 3, :o2, 1837645200
-
1
tz.transition 2028, 10, :o1, 1856394000
-
1
tz.transition 2029, 3, :o2, 1869094800
-
1
tz.transition 2029, 10, :o1, 1887843600
-
1
tz.transition 2030, 3, :o2, 1901149200
-
1
tz.transition 2030, 10, :o1, 1919293200
-
1
tz.transition 2031, 3, :o2, 1932598800
-
1
tz.transition 2031, 10, :o1, 1950742800
-
1
tz.transition 2032, 3, :o2, 1964048400
-
1
tz.transition 2032, 10, :o1, 1982797200
-
1
tz.transition 2033, 3, :o2, 1995498000
-
1
tz.transition 2033, 10, :o1, 2014246800
-
1
tz.transition 2034, 3, :o2, 2026947600
-
1
tz.transition 2034, 10, :o1, 2045696400
-
1
tz.transition 2035, 3, :o2, 2058397200
-
1
tz.transition 2035, 10, :o1, 2077146000
-
1
tz.transition 2036, 3, :o2, 2090451600
-
1
tz.transition 2036, 10, :o1, 2108595600
-
1
tz.transition 2037, 3, :o2, 2121901200
-
1
tz.transition 2037, 10, :o1, 2140045200
-
1
tz.transition 2038, 3, :o2, 59172253, 24
-
1
tz.transition 2038, 10, :o1, 59177461, 24
-
1
tz.transition 2039, 3, :o2, 59180989, 24
-
1
tz.transition 2039, 10, :o1, 59186197, 24
-
1
tz.transition 2040, 3, :o2, 59189725, 24
-
1
tz.transition 2040, 10, :o1, 59194933, 24
-
1
tz.transition 2041, 3, :o2, 59198629, 24
-
1
tz.transition 2041, 10, :o1, 59203669, 24
-
1
tz.transition 2042, 3, :o2, 59207365, 24
-
1
tz.transition 2042, 10, :o1, 59212405, 24
-
1
tz.transition 2043, 3, :o2, 59216101, 24
-
1
tz.transition 2043, 10, :o1, 59221141, 24
-
1
tz.transition 2044, 3, :o2, 59224837, 24
-
1
tz.transition 2044, 10, :o1, 59230045, 24
-
1
tz.transition 2045, 3, :o2, 59233573, 24
-
1
tz.transition 2045, 10, :o1, 59238781, 24
-
1
tz.transition 2046, 3, :o2, 59242309, 24
-
1
tz.transition 2046, 10, :o1, 59247517, 24
-
1
tz.transition 2047, 3, :o2, 59251213, 24
-
1
tz.transition 2047, 10, :o1, 59256253, 24
-
1
tz.transition 2048, 3, :o2, 59259949, 24
-
1
tz.transition 2048, 10, :o1, 59264989, 24
-
1
tz.transition 2049, 3, :o2, 59268685, 24
-
1
tz.transition 2049, 10, :o1, 59273893, 24
-
1
tz.transition 2050, 3, :o2, 59277421, 24
-
1
tz.transition 2050, 10, :o1, 59282629, 24
-
end
-
end
-
end
-
end
-
end
-
1
module TZInfo
-
1
module Definitions
-
1
module America
-
1
module Guatemala
-
1
include TimezoneDefinition
-
-
1
timezone 'America/Guatemala' do |tz|
-
1
tz.offset :o0, -21724, 0, :LMT
-
1
tz.offset :o1, -21600, 0, :CST
-
1
tz.offset :o2, -21600, 3600, :CDT
-
-
1
tz.transition 1918, 10, :o1, 52312429831, 21600
-
1
tz.transition 1973, 11, :o2, 123055200
-
1
tz.transition 1974, 2, :o1, 130914000
-
1
tz.transition 1983, 5, :o2, 422344800
-
1
tz.transition 1983, 9, :o1, 433054800
-
1
tz.transition 1991, 3, :o2, 669708000
-
1
tz.transition 1991, 9, :o1, 684219600
-
1
tz.transition 2006, 4, :o2, 1146376800
-
1
tz.transition 2006, 10, :o1, 1159678800
-
end
-
end
-
end
-
end
-
end
-
1
module TZInfo
-
1
module Definitions
-
1
module America
-
1
module Guyana
-
1
include TimezoneDefinition
-
-
1
timezone 'America/Guyana' do |tz|
-
1
tz.offset :o0, -13960, 0, :LMT
-
1
tz.offset :o1, -13500, 0, :GBGT
-
1
tz.offset :o2, -13500, 0, :GYT
-
1
tz.offset :o3, -10800, 0, :GYT
-
1
tz.offset :o4, -14400, 0, :GYT
-
-
1
tz.transition 1915, 3, :o1, 5228404549, 2160
-
1
tz.transition 1966, 5, :o2, 78056693, 32
-
1
tz.transition 1975, 7, :o3, 176010300
-
1
tz.transition 1991, 1, :o4, 662698800
-
end
-
end
-
end
-
end
-
end
-
1
module TZInfo
-
1
module Definitions
-
1
module America
-
1
module Halifax
-
1
include TimezoneDefinition
-
-
1
timezone 'America/Halifax' do |tz|
-
1
tz.offset :o0, -15264, 0, :LMT
-
1
tz.offset :o1, -14400, 0, :AST
-
1
tz.offset :o2, -14400, 3600, :ADT
-
1
tz.offset :o3, -14400, 3600, :AWT
-
1
tz.offset :o4, -14400, 3600, :APT
-
-
1
tz.transition 1902, 6, :o1, 724774703, 300
-
1
tz.transition 1916, 4, :o2, 7262864, 3
-
1
tz.transition 1916, 10, :o1, 19369101, 8
-
1
tz.transition 1918, 4, :o2, 9686791, 4
-
1
tz.transition 1918, 10, :o1, 58125449, 24
-
1
tz.transition 1920, 5, :o2, 7267361, 3
-
1
tz.transition 1920, 8, :o1, 19380525, 8
-
1
tz.transition 1921, 5, :o2, 7268447, 3
-
1
tz.transition 1921, 9, :o1, 19383501, 8
-
1
tz.transition 1922, 4, :o2, 7269524, 3
-
1
tz.transition 1922, 9, :o1, 19386421, 8
-
1
tz.transition 1923, 5, :o2, 7270637, 3
-
1
tz.transition 1923, 9, :o1, 19389333, 8
-
1
tz.transition 1924, 5, :o2, 7271729, 3
-
1
tz.transition 1924, 9, :o1, 19392349, 8
-
1
tz.transition 1925, 5, :o2, 7272821, 3
-
1
tz.transition 1925, 9, :o1, 19395373, 8
-
1
tz.transition 1926, 5, :o2, 7273955, 3
-
1
tz.transition 1926, 9, :o1, 19398173, 8
-
1
tz.transition 1927, 5, :o2, 7275005, 3
-
1
tz.transition 1927, 9, :o1, 19401197, 8
-
1
tz.transition 1928, 5, :o2, 7276139, 3
-
1
tz.transition 1928, 9, :o1, 19403989, 8
-
1
tz.transition 1929, 5, :o2, 7277231, 3
-
1
tz.transition 1929, 9, :o1, 19406861, 8
-
1
tz.transition 1930, 5, :o2, 7278323, 3
-
1
tz.transition 1930, 9, :o1, 19409877, 8
-
1
tz.transition 1931, 5, :o2, 7279415, 3
-
1
tz.transition 1931, 9, :o1, 19412901, 8
-
1
tz.transition 1932, 5, :o2, 7280486, 3
-
1
tz.transition 1932, 9, :o1, 19415813, 8
-
1
tz.transition 1933, 4, :o2, 7281578, 3
-
1
tz.transition 1933, 10, :o1, 19418781, 8
-
1
tz.transition 1934, 5, :o2, 7282733, 3
-
1
tz.transition 1934, 9, :o1, 19421573, 8
-
1
tz.transition 1935, 6, :o2, 7283867, 3
-
1
tz.transition 1935, 9, :o1, 19424605, 8
-
1
tz.transition 1936, 6, :o2, 7284962, 3
-
1
tz.transition 1936, 9, :o1, 19427405, 8
-
1
tz.transition 1937, 5, :o2, 7285967, 3
-
1
tz.transition 1937, 9, :o1, 19430429, 8
-
1
tz.transition 1938, 5, :o2, 7287059, 3
-
1
tz.transition 1938, 9, :o1, 19433341, 8
-
1
tz.transition 1939, 5, :o2, 7288235, 3
-
1
tz.transition 1939, 9, :o1, 19436253, 8
-
1
tz.transition 1940, 5, :o2, 7289264, 3
-
1
tz.transition 1940, 9, :o1, 19439221, 8
-
1
tz.transition 1941, 5, :o2, 7290356, 3
-
1
tz.transition 1941, 9, :o1, 19442133, 8
-
1
tz.transition 1942, 2, :o3, 9721599, 4
-
1
tz.transition 1945, 8, :o4, 58360379, 24
-
1
tz.transition 1945, 9, :o1, 58361489, 24
-
1
tz.transition 1946, 4, :o2, 9727755, 4
-
1
tz.transition 1946, 9, :o1, 58370225, 24
-
1
tz.transition 1947, 4, :o2, 9729211, 4
-
1
tz.transition 1947, 9, :o1, 58378961, 24
-
1
tz.transition 1948, 4, :o2, 9730667, 4
-
1
tz.transition 1948, 9, :o1, 58387697, 24
-
1
tz.transition 1949, 4, :o2, 9732123, 4
-
1
tz.transition 1949, 9, :o1, 58396433, 24
-
1
tz.transition 1951, 4, :o2, 9735063, 4
-
1
tz.transition 1951, 9, :o1, 58414073, 24
-
1
tz.transition 1952, 4, :o2, 9736519, 4
-
1
tz.transition 1952, 9, :o1, 58422809, 24
-
1
tz.transition 1953, 4, :o2, 9737975, 4
-
1
tz.transition 1953, 9, :o1, 58431545, 24
-
1
tz.transition 1954, 4, :o2, 9739431, 4
-
1
tz.transition 1954, 9, :o1, 58440281, 24
-
1
tz.transition 1956, 4, :o2, 9742371, 4
-
1
tz.transition 1956, 9, :o1, 58457921, 24
-
1
tz.transition 1957, 4, :o2, 9743827, 4
-
1
tz.transition 1957, 9, :o1, 58466657, 24
-
1
tz.transition 1958, 4, :o2, 9745283, 4
-
1
tz.transition 1958, 9, :o1, 58475393, 24
-
1
tz.transition 1959, 4, :o2, 9746739, 4
-
1
tz.transition 1959, 9, :o1, 58484129, 24
-
1
tz.transition 1962, 4, :o2, 9751135, 4
-
1
tz.transition 1962, 10, :o1, 58511177, 24
-
1
tz.transition 1963, 4, :o2, 9752591, 4
-
1
tz.transition 1963, 10, :o1, 58519913, 24
-
1
tz.transition 1964, 4, :o2, 9754047, 4
-
1
tz.transition 1964, 10, :o1, 58528649, 24
-
1
tz.transition 1965, 4, :o2, 9755503, 4
-
1
tz.transition 1965, 10, :o1, 58537553, 24
-
1
tz.transition 1966, 4, :o2, 9756959, 4
-
1
tz.transition 1966, 10, :o1, 58546289, 24
-
1
tz.transition 1967, 4, :o2, 9758443, 4
-
1
tz.transition 1967, 10, :o1, 58555025, 24
-
1
tz.transition 1968, 4, :o2, 9759899, 4
-
1
tz.transition 1968, 10, :o1, 58563761, 24
-
1
tz.transition 1969, 4, :o2, 9761355, 4
-
1
tz.transition 1969, 10, :o1, 58572497, 24
-
1
tz.transition 1970, 4, :o2, 9957600
-
1
tz.transition 1970, 10, :o1, 25678800
-
1
tz.transition 1971, 4, :o2, 41407200
-
1
tz.transition 1971, 10, :o1, 57733200
-
1
tz.transition 1972, 4, :o2, 73461600
-
1
tz.transition 1972, 10, :o1, 89182800
-
1
tz.transition 1973, 4, :o2, 104911200
-
1
tz.transition 1973, 10, :o1, 120632400
-
1
tz.transition 1974, 4, :o2, 136360800
-
1
tz.transition 1974, 10, :o1, 152082000
-
1
tz.transition 1975, 4, :o2, 167810400
-
1
tz.transition 1975, 10, :o1, 183531600
-
1
tz.transition 1976, 4, :o2, 199260000
-
1
tz.transition 1976, 10, :o1, 215586000
-
1
tz.transition 1977, 4, :o2, 230709600
-
1
tz.transition 1977, 10, :o1, 247035600
-
1
tz.transition 1978, 4, :o2, 262764000
-
1
tz.transition 1978, 10, :o1, 278485200
-
1
tz.transition 1979, 4, :o2, 294213600
-
1
tz.transition 1979, 10, :o1, 309934800
-
1
tz.transition 1980, 4, :o2, 325663200
-
1
tz.transition 1980, 10, :o1, 341384400
-
1
tz.transition 1981, 4, :o2, 357112800
-
1
tz.transition 1981, 10, :o1, 372834000
-
1
tz.transition 1982, 4, :o2, 388562400
-
1
tz.transition 1982, 10, :o1, 404888400
-
1
tz.transition 1983, 4, :o2, 420012000
-
1
tz.transition 1983, 10, :o1, 436338000
-
1
tz.transition 1984, 4, :o2, 452066400
-
1
tz.transition 1984, 10, :o1, 467787600
-
1
tz.transition 1985, 4, :o2, 483516000
-
1
tz.transition 1985, 10, :o1, 499237200
-
1
tz.transition 1986, 4, :o2, 514965600
-
1
tz.transition 1986, 10, :o1, 530686800
-
1
tz.transition 1987, 4, :o2, 544600800
-
1
tz.transition 1987, 10, :o1, 562136400
-
1
tz.transition 1988, 4, :o2, 576050400
-
1
tz.transition 1988, 10, :o1, 594190800
-
1
tz.transition 1989, 4, :o2, 607500000
-
1
tz.transition 1989, 10, :o1, 625640400
-
1
tz.transition 1990, 4, :o2, 638949600
-
1
tz.transition 1990, 10, :o1, 657090000
-
1
tz.transition 1991, 4, :o2, 671004000
-
1
tz.transition 1991, 10, :o1, 688539600
-
1
tz.transition 1992, 4, :o2, 702453600
-
1
tz.transition 1992, 10, :o1, 719989200
-
1
tz.transition 1993, 4, :o2, 733903200
-
1
tz.transition 1993, 10, :o1, 752043600
-
1
tz.transition 1994, 4, :o2, 765352800
-
1
tz.transition 1994, 10, :o1, 783493200
-
1
tz.transition 1995, 4, :o2, 796802400
-
1
tz.transition 1995, 10, :o1, 814942800
-
1
tz.transition 1996, 4, :o2, 828856800
-
1
tz.transition 1996, 10, :o1, 846392400
-
1
tz.transition 1997, 4, :o2, 860306400
-
1
tz.transition 1997, 10, :o1, 877842000
-
1
tz.transition 1998, 4, :o2, 891756000
-
1
tz.transition 1998, 10, :o1, 909291600
-
1
tz.transition 1999, 4, :o2, 923205600
-
1
tz.transition 1999, 10, :o1, 941346000
-
1
tz.transition 2000, 4, :o2, 954655200
-
1
tz.transition 2000, 10, :o1, 972795600
-
1
tz.transition 2001, 4, :o2, 986104800
-
1
tz.transition 2001, 10, :o1, 1004245200
-
1
tz.transition 2002, 4, :o2, 1018159200
-
1
tz.transition 2002, 10, :o1, 1035694800
-
1
tz.transition 2003, 4, :o2, 1049608800
-
1
tz.transition 2003, 10, :o1, 1067144400
-
1
tz.transition 2004, 4, :o2, 1081058400
-
1
tz.transition 2004, 10, :o1, 1099198800
-
1
tz.transition 2005, 4, :o2, 1112508000
-
1
tz.transition 2005, 10, :o1, 1130648400
-
1
tz.transition 2006, 4, :o2, 1143957600
-
1
tz.transition 2006, 10, :o1, 1162098000
-
1
tz.transition 2007, 3, :o2, 1173592800
-
1
tz.transition 2007, 11, :o1, 1194152400
-
1
tz.transition 2008, 3, :o2, 1205042400
-
1
tz.transition 2008, 11, :o1, 1225602000
-
1
tz.transition 2009, 3, :o2, 1236492000
-
1
tz.transition 2009, 11, :o1, 1257051600
-
1
tz.transition 2010, 3, :o2, 1268546400
-
1
tz.transition 2010, 11, :o1, 1289106000
-
1
tz.transition 2011, 3, :o2, 1299996000
-
1
tz.transition 2011, 11, :o1, 1320555600
-
1
tz.transition 2012, 3, :o2, 1331445600
-
1
tz.transition 2012, 11, :o1, 1352005200
-
1
tz.transition 2013, 3, :o2, 1362895200
-
1
tz.transition 2013, 11, :o1, 1383454800
-
1
tz.transition 2014, 3, :o2, 1394344800
-
1
tz.transition 2014, 11, :o1, 1414904400
-
1
tz.transition 2015, 3, :o2, 1425794400
-
1
tz.transition 2015, 11, :o1, 1446354000
-
1
tz.transition 2016, 3, :o2, 1457848800
-
1
tz.transition 2016, 11, :o1, 1478408400
-
1
tz.transition 2017, 3, :o2, 1489298400
-
1
tz.transition 2017, 11, :o1, 1509858000
-
1
tz.transition 2018, 3, :o2, 1520748000
-
1
tz.transition 2018, 11, :o1, 1541307600
-
1
tz.transition 2019, 3, :o2, 1552197600
-
1
tz.transition 2019, 11, :o1, 1572757200
-
1
tz.transition 2020, 3, :o2, 1583647200
-
1
tz.transition 2020, 11, :o1, 1604206800
-
1
tz.transition 2021, 3, :o2, 1615701600
-
1
tz.transition 2021, 11, :o1, 1636261200
-
1
tz.transition 2022, 3, :o2, 1647151200
-
1
tz.transition 2022, 11, :o1, 1667710800
-
1
tz.transition 2023, 3, :o2, 1678600800
-
1
tz.transition 2023, 11, :o1, 1699160400
-
1
tz.transition 2024, 3, :o2, 1710050400
-
1
tz.transition 2024, 11, :o1, 1730610000
-
1
tz.transition 2025, 3, :o2, 1741500000
-
1
tz.transition 2025, 11, :o1, 1762059600
-
1
tz.transition 2026, 3, :o2, 1772949600
-
1
tz.transition 2026, 11, :o1, 1793509200
-
1
tz.transition 2027, 3, :o2, 1805004000
-
1
tz.transition 2027, 11, :o1, 1825563600
-
1
tz.transition 2028, 3, :o2, 1836453600
-
1
tz.transition 2028, 11, :o1, 1857013200
-
1
tz.transition 2029, 3, :o2, 1867903200
-
1
tz.transition 2029, 11, :o1, 1888462800
-
1
tz.transition 2030, 3, :o2, 1899352800
-
1
tz.transition 2030, 11, :o1, 1919912400
-
1
tz.transition 2031, 3, :o2, 1930802400
-
1
tz.transition 2031, 11, :o1, 1951362000
-
1
tz.transition 2032, 3, :o2, 1962856800
-
1
tz.transition 2032, 11, :o1, 1983416400
-
1
tz.transition 2033, 3, :o2, 1994306400
-
1
tz.transition 2033, 11, :o1, 2014866000
-
1
tz.transition 2034, 3, :o2, 2025756000
-
1
tz.transition 2034, 11, :o1, 2046315600
-
1
tz.transition 2035, 3, :o2, 2057205600
-
1
tz.transition 2035, 11, :o1, 2077765200
-
1
tz.transition 2036, 3, :o2, 2088655200
-
1
tz.transition 2036, 11, :o1, 2109214800
-
1
tz.transition 2037, 3, :o2, 2120104800
-
1
tz.transition 2037, 11, :o1, 2140664400
-
1
tz.transition 2038, 3, :o2, 9861987, 4
-
1
tz.transition 2038, 11, :o1, 59177633, 24
-
1
tz.transition 2039, 3, :o2, 9863443, 4
-
1
tz.transition 2039, 11, :o1, 59186369, 24
-
1
tz.transition 2040, 3, :o2, 9864899, 4
-
1
tz.transition 2040, 11, :o1, 59195105, 24
-
1
tz.transition 2041, 3, :o2, 9866355, 4
-
1
tz.transition 2041, 11, :o1, 59203841, 24
-
1
tz.transition 2042, 3, :o2, 9867811, 4
-
1
tz.transition 2042, 11, :o1, 59212577, 24
-
1
tz.transition 2043, 3, :o2, 9869267, 4
-
1
tz.transition 2043, 11, :o1, 59221313, 24
-
1
tz.transition 2044, 3, :o2, 9870751, 4
-
1
tz.transition 2044, 11, :o1, 59230217, 24
-
1
tz.transition 2045, 3, :o2, 9872207, 4
-
1
tz.transition 2045, 11, :o1, 59238953, 24
-
1
tz.transition 2046, 3, :o2, 9873663, 4
-
1
tz.transition 2046, 11, :o1, 59247689, 24
-
1
tz.transition 2047, 3, :o2, 9875119, 4
-
1
tz.transition 2047, 11, :o1, 59256425, 24
-
1
tz.transition 2048, 3, :o2, 9876575, 4
-
1
tz.transition 2048, 11, :o1, 59265161, 24
-
1
tz.transition 2049, 3, :o2, 9878059, 4
-
1
tz.transition 2049, 11, :o1, 59274065, 24
-
1
tz.transition 2050, 3, :o2, 9879515, 4
-
1
tz.transition 2050, 11, :o1, 59282801, 24
-
end
-
end
-
end
-
end
-
end
-
1
module TZInfo
-
1
module Definitions
-
1
module America
-
1
module Indiana
-
1
module Indianapolis
-
1
include TimezoneDefinition
-
-
1
timezone 'America/Indiana/Indianapolis' do |tz|
-
1
tz.offset :o0, -20678, 0, :LMT
-
1
tz.offset :o1, -21600, 0, :CST
-
1
tz.offset :o2, -21600, 3600, :CDT
-
1
tz.offset :o3, -21600, 3600, :CWT
-
1
tz.offset :o4, -21600, 3600, :CPT
-
1
tz.offset :o5, -18000, 0, :EST
-
1
tz.offset :o6, -18000, 3600, :EDT
-
-
1
tz.transition 1883, 11, :o1, 9636533, 4
-
1
tz.transition 1918, 3, :o2, 14530103, 6
-
1
tz.transition 1918, 10, :o1, 58125451, 24
-
1
tz.transition 1919, 3, :o2, 14532287, 6
-
1
tz.transition 1919, 10, :o1, 58134187, 24
-
1
tz.transition 1941, 6, :o2, 14581007, 6
-
1
tz.transition 1941, 9, :o1, 58326379, 24
-
1
tz.transition 1942, 2, :o3, 14582399, 6
-
1
tz.transition 1945, 8, :o4, 58360379, 24
-
1
tz.transition 1945, 9, :o1, 58361491, 24
-
1
tz.transition 1946, 4, :o2, 14591633, 6
-
1
tz.transition 1946, 9, :o1, 58370227, 24
-
1
tz.transition 1947, 4, :o2, 14593817, 6
-
1
tz.transition 1947, 9, :o1, 58378963, 24
-
1
tz.transition 1948, 4, :o2, 14596001, 6
-
1
tz.transition 1948, 9, :o1, 58387699, 24
-
1
tz.transition 1949, 4, :o2, 14598185, 6
-
1
tz.transition 1949, 9, :o1, 58396435, 24
-
1
tz.transition 1950, 4, :o2, 14600411, 6
-
1
tz.transition 1950, 9, :o1, 58405171, 24
-
1
tz.transition 1951, 4, :o2, 14602595, 6
-
1
tz.transition 1951, 9, :o1, 58414075, 24
-
1
tz.transition 1952, 4, :o2, 14604779, 6
-
1
tz.transition 1952, 9, :o1, 58422811, 24
-
1
tz.transition 1953, 4, :o2, 14606963, 6
-
1
tz.transition 1953, 9, :o1, 58431547, 24
-
1
tz.transition 1954, 4, :o2, 14609147, 6
-
1
tz.transition 1954, 9, :o1, 58440283, 24
-
1
tz.transition 1955, 4, :o5, 14611331, 6
-
1
tz.transition 1957, 9, :o1, 58466659, 24
-
1
tz.transition 1958, 4, :o5, 14617925, 6
-
1
tz.transition 1969, 4, :o6, 58568131, 24
-
1
tz.transition 1969, 10, :o5, 9762083, 4
-
1
tz.transition 1970, 4, :o6, 9961200
-
1
tz.transition 1970, 10, :o5, 25682400
-
1
tz.transition 2006, 4, :o6, 1143961200
-
1
tz.transition 2006, 10, :o5, 1162101600
-
1
tz.transition 2007, 3, :o6, 1173596400
-
1
tz.transition 2007, 11, :o5, 1194156000
-
1
tz.transition 2008, 3, :o6, 1205046000
-
1
tz.transition 2008, 11, :o5, 1225605600
-
1
tz.transition 2009, 3, :o6, 1236495600
-
1
tz.transition 2009, 11, :o5, 1257055200
-
1
tz.transition 2010, 3, :o6, 1268550000
-
1
tz.transition 2010, 11, :o5, 1289109600
-
1
tz.transition 2011, 3, :o6, 1299999600
-
1
tz.transition 2011, 11, :o5, 1320559200
-
1
tz.transition 2012, 3, :o6, 1331449200
-
1
tz.transition 2012, 11, :o5, 1352008800
-
1
tz.transition 2013, 3, :o6, 1362898800
-
1
tz.transition 2013, 11, :o5, 1383458400
-
1
tz.transition 2014, 3, :o6, 1394348400
-
1
tz.transition 2014, 11, :o5, 1414908000
-
1
tz.transition 2015, 3, :o6, 1425798000
-
1
tz.transition 2015, 11, :o5, 1446357600
-
1
tz.transition 2016, 3, :o6, 1457852400
-
1
tz.transition 2016, 11, :o5, 1478412000
-
1
tz.transition 2017, 3, :o6, 1489302000
-
1
tz.transition 2017, 11, :o5, 1509861600
-
1
tz.transition 2018, 3, :o6, 1520751600
-
1
tz.transition 2018, 11, :o5, 1541311200
-
1
tz.transition 2019, 3, :o6, 1552201200
-
1
tz.transition 2019, 11, :o5, 1572760800
-
1
tz.transition 2020, 3, :o6, 1583650800
-
1
tz.transition 2020, 11, :o5, 1604210400
-
1
tz.transition 2021, 3, :o6, 1615705200
-
1
tz.transition 2021, 11, :o5, 1636264800
-
1
tz.transition 2022, 3, :o6, 1647154800
-
1
tz.transition 2022, 11, :o5, 1667714400
-
1
tz.transition 2023, 3, :o6, 1678604400
-
1
tz.transition 2023, 11, :o5, 1699164000
-
1
tz.transition 2024, 3, :o6, 1710054000
-
1
tz.transition 2024, 11, :o5, 1730613600
-
1
tz.transition 2025, 3, :o6, 1741503600
-
1
tz.transition 2025, 11, :o5, 1762063200
-
1
tz.transition 2026, 3, :o6, 1772953200
-
1
tz.transition 2026, 11, :o5, 1793512800
-
1
tz.transition 2027, 3, :o6, 1805007600
-
1
tz.transition 2027, 11, :o5, 1825567200
-
1
tz.transition 2028, 3, :o6, 1836457200
-
1
tz.transition 2028, 11, :o5, 1857016800
-
1
tz.transition 2029, 3, :o6, 1867906800
-
1
tz.transition 2029, 11, :o5, 1888466400
-
1
tz.transition 2030, 3, :o6, 1899356400
-
1
tz.transition 2030, 11, :o5, 1919916000
-
1
tz.transition 2031, 3, :o6, 1930806000
-
1
tz.transition 2031, 11, :o5, 1951365600
-
1
tz.transition 2032, 3, :o6, 1962860400
-
1
tz.transition 2032, 11, :o5, 1983420000
-
1
tz.transition 2033, 3, :o6, 1994310000
-
1
tz.transition 2033, 11, :o5, 2014869600
-
1
tz.transition 2034, 3, :o6, 2025759600
-
1
tz.transition 2034, 11, :o5, 2046319200
-
1
tz.transition 2035, 3, :o6, 2057209200
-
1
tz.transition 2035, 11, :o5, 2077768800
-
1
tz.transition 2036, 3, :o6, 2088658800
-
1
tz.transition 2036, 11, :o5, 2109218400
-
1
tz.transition 2037, 3, :o6, 2120108400
-
1
tz.transition 2037, 11, :o5, 2140668000
-
1
tz.transition 2038, 3, :o6, 59171923, 24
-
1
tz.transition 2038, 11, :o5, 9862939, 4
-
1
tz.transition 2039, 3, :o6, 59180659, 24
-
1
tz.transition 2039, 11, :o5, 9864395, 4
-
1
tz.transition 2040, 3, :o6, 59189395, 24
-
1
tz.transition 2040, 11, :o5, 9865851, 4
-
1
tz.transition 2041, 3, :o6, 59198131, 24
-
1
tz.transition 2041, 11, :o5, 9867307, 4
-
1
tz.transition 2042, 3, :o6, 59206867, 24
-
1
tz.transition 2042, 11, :o5, 9868763, 4
-
1
tz.transition 2043, 3, :o6, 59215603, 24
-
1
tz.transition 2043, 11, :o5, 9870219, 4
-
1
tz.transition 2044, 3, :o6, 59224507, 24
-
1
tz.transition 2044, 11, :o5, 9871703, 4
-
1
tz.transition 2045, 3, :o6, 59233243, 24
-
1
tz.transition 2045, 11, :o5, 9873159, 4
-
1
tz.transition 2046, 3, :o6, 59241979, 24
-
1
tz.transition 2046, 11, :o5, 9874615, 4
-
1
tz.transition 2047, 3, :o6, 59250715, 24
-
1
tz.transition 2047, 11, :o5, 9876071, 4
-
1
tz.transition 2048, 3, :o6, 59259451, 24
-
1
tz.transition 2048, 11, :o5, 9877527, 4
-
1
tz.transition 2049, 3, :o6, 59268355, 24
-
1
tz.transition 2049, 11, :o5, 9879011, 4
-
1
tz.transition 2050, 3, :o6, 59277091, 24
-
1
tz.transition 2050, 11, :o5, 9880467, 4
-
end
-
end
-
end
-
end
-
end
-
end
-
1
module TZInfo
-
1
module Definitions
-
1
module America
-
1
module Juneau
-
1
include TimezoneDefinition
-
-
1
timezone 'America/Juneau' do |tz|
-
1
tz.offset :o0, 54139, 0, :LMT
-
1
tz.offset :o1, -32261, 0, :LMT
-
1
tz.offset :o2, -28800, 0, :PST
-
1
tz.offset :o3, -28800, 3600, :PWT
-
1
tz.offset :o4, -28800, 3600, :PPT
-
1
tz.offset :o5, -28800, 3600, :PDT
-
1
tz.offset :o6, -32400, 3600, :YDT
-
1
tz.offset :o7, -32400, 0, :YST
-
1
tz.offset :o8, -32400, 0, :AKST
-
1
tz.offset :o9, -32400, 3600, :AKDT
-
-
1
tz.transition 1867, 10, :o1, 207641393861, 86400
-
1
tz.transition 1900, 8, :o2, 208677805061, 86400
-
1
tz.transition 1942, 2, :o3, 29164799, 12
-
1
tz.transition 1945, 8, :o4, 58360379, 24
-
1
tz.transition 1945, 9, :o2, 19453831, 8
-
1
tz.transition 1969, 4, :o5, 29284067, 12
-
1
tz.transition 1969, 10, :o2, 19524167, 8
-
1
tz.transition 1970, 4, :o5, 9972000
-
1
tz.transition 1970, 10, :o2, 25693200
-
1
tz.transition 1971, 4, :o5, 41421600
-
1
tz.transition 1971, 10, :o2, 57747600
-
1
tz.transition 1972, 4, :o5, 73476000
-
1
tz.transition 1972, 10, :o2, 89197200
-
1
tz.transition 1973, 4, :o5, 104925600
-
1
tz.transition 1973, 10, :o2, 120646800
-
1
tz.transition 1974, 1, :o5, 126698400
-
1
tz.transition 1974, 10, :o2, 152096400
-
1
tz.transition 1975, 2, :o5, 162381600
-
1
tz.transition 1975, 10, :o2, 183546000
-
1
tz.transition 1976, 4, :o5, 199274400
-
1
tz.transition 1976, 10, :o2, 215600400
-
1
tz.transition 1977, 4, :o5, 230724000
-
1
tz.transition 1977, 10, :o2, 247050000
-
1
tz.transition 1978, 4, :o5, 262778400
-
1
tz.transition 1978, 10, :o2, 278499600
-
1
tz.transition 1979, 4, :o5, 294228000
-
1
tz.transition 1979, 10, :o2, 309949200
-
1
tz.transition 1980, 4, :o6, 325677600
-
1
tz.transition 1980, 10, :o2, 341402400
-
1
tz.transition 1981, 4, :o5, 357127200
-
1
tz.transition 1981, 10, :o2, 372848400
-
1
tz.transition 1982, 4, :o5, 388576800
-
1
tz.transition 1982, 10, :o2, 404902800
-
1
tz.transition 1983, 4, :o5, 420026400
-
1
tz.transition 1983, 10, :o7, 436352400
-
1
tz.transition 1983, 11, :o8, 439030800
-
1
tz.transition 1984, 4, :o9, 452084400
-
1
tz.transition 1984, 10, :o8, 467805600
-
1
tz.transition 1985, 4, :o9, 483534000
-
1
tz.transition 1985, 10, :o8, 499255200
-
1
tz.transition 1986, 4, :o9, 514983600
-
1
tz.transition 1986, 10, :o8, 530704800
-
1
tz.transition 1987, 4, :o9, 544618800
-
1
tz.transition 1987, 10, :o8, 562154400
-
1
tz.transition 1988, 4, :o9, 576068400
-
1
tz.transition 1988, 10, :o8, 594208800
-
1
tz.transition 1989, 4, :o9, 607518000
-
1
tz.transition 1989, 10, :o8, 625658400
-
1
tz.transition 1990, 4, :o9, 638967600
-
1
tz.transition 1990, 10, :o8, 657108000
-
1
tz.transition 1991, 4, :o9, 671022000
-
1
tz.transition 1991, 10, :o8, 688557600
-
1
tz.transition 1992, 4, :o9, 702471600
-
1
tz.transition 1992, 10, :o8, 720007200
-
1
tz.transition 1993, 4, :o9, 733921200
-
1
tz.transition 1993, 10, :o8, 752061600
-
1
tz.transition 1994, 4, :o9, 765370800
-
1
tz.transition 1994, 10, :o8, 783511200
-
1
tz.transition 1995, 4, :o9, 796820400
-
1
tz.transition 1995, 10, :o8, 814960800
-
1
tz.transition 1996, 4, :o9, 828874800
-
1
tz.transition 1996, 10, :o8, 846410400
-
1
tz.transition 1997, 4, :o9, 860324400
-
1
tz.transition 1997, 10, :o8, 877860000
-
1
tz.transition 1998, 4, :o9, 891774000
-
1
tz.transition 1998, 10, :o8, 909309600
-
1
tz.transition 1999, 4, :o9, 923223600
-
1
tz.transition 1999, 10, :o8, 941364000
-
1
tz.transition 2000, 4, :o9, 954673200
-
1
tz.transition 2000, 10, :o8, 972813600
-
1
tz.transition 2001, 4, :o9, 986122800
-
1
tz.transition 2001, 10, :o8, 1004263200
-
1
tz.transition 2002, 4, :o9, 1018177200
-
1
tz.transition 2002, 10, :o8, 1035712800
-
1
tz.transition 2003, 4, :o9, 1049626800
-
1
tz.transition 2003, 10, :o8, 1067162400
-
1
tz.transition 2004, 4, :o9, 1081076400
-
1
tz.transition 2004, 10, :o8, 1099216800
-
1
tz.transition 2005, 4, :o9, 1112526000
-
1
tz.transition 2005, 10, :o8, 1130666400
-
1
tz.transition 2006, 4, :o9, 1143975600
-
1
tz.transition 2006, 10, :o8, 1162116000
-
1
tz.transition 2007, 3, :o9, 1173610800
-
1
tz.transition 2007, 11, :o8, 1194170400
-
1
tz.transition 2008, 3, :o9, 1205060400
-
1
tz.transition 2008, 11, :o8, 1225620000
-
1
tz.transition 2009, 3, :o9, 1236510000
-
1
tz.transition 2009, 11, :o8, 1257069600
-
1
tz.transition 2010, 3, :o9, 1268564400
-
1
tz.transition 2010, 11, :o8, 1289124000
-
1
tz.transition 2011, 3, :o9, 1300014000
-
1
tz.transition 2011, 11, :o8, 1320573600
-
1
tz.transition 2012, 3, :o9, 1331463600
-
1
tz.transition 2012, 11, :o8, 1352023200
-
1
tz.transition 2013, 3, :o9, 1362913200
-
1
tz.transition 2013, 11, :o8, 1383472800
-
1
tz.transition 2014, 3, :o9, 1394362800
-
1
tz.transition 2014, 11, :o8, 1414922400
-
1
tz.transition 2015, 3, :o9, 1425812400
-
1
tz.transition 2015, 11, :o8, 1446372000
-
1
tz.transition 2016, 3, :o9, 1457866800
-
1
tz.transition 2016, 11, :o8, 1478426400
-
1
tz.transition 2017, 3, :o9, 1489316400
-
1
tz.transition 2017, 11, :o8, 1509876000
-
1
tz.transition 2018, 3, :o9, 1520766000
-
1
tz.transition 2018, 11, :o8, 1541325600
-
1
tz.transition 2019, 3, :o9, 1552215600
-
1
tz.transition 2019, 11, :o8, 1572775200
-
1
tz.transition 2020, 3, :o9, 1583665200
-
1
tz.transition 2020, 11, :o8, 1604224800
-
1
tz.transition 2021, 3, :o9, 1615719600
-
1
tz.transition 2021, 11, :o8, 1636279200
-
1
tz.transition 2022, 3, :o9, 1647169200
-
1
tz.transition 2022, 11, :o8, 1667728800
-
1
tz.transition 2023, 3, :o9, 1678618800
-
1
tz.transition 2023, 11, :o8, 1699178400
-
1
tz.transition 2024, 3, :o9, 1710068400
-
1
tz.transition 2024, 11, :o8, 1730628000
-
1
tz.transition 2025, 3, :o9, 1741518000
-
1
tz.transition 2025, 11, :o8, 1762077600
-
1
tz.transition 2026, 3, :o9, 1772967600
-
1
tz.transition 2026, 11, :o8, 1793527200
-
1
tz.transition 2027, 3, :o9, 1805022000
-
1
tz.transition 2027, 11, :o8, 1825581600
-
1
tz.transition 2028, 3, :o9, 1836471600
-
1
tz.transition 2028, 11, :o8, 1857031200
-
1
tz.transition 2029, 3, :o9, 1867921200
-
1
tz.transition 2029, 11, :o8, 1888480800
-
1
tz.transition 2030, 3, :o9, 1899370800
-
1
tz.transition 2030, 11, :o8, 1919930400
-
1
tz.transition 2031, 3, :o9, 1930820400
-
1
tz.transition 2031, 11, :o8, 1951380000
-
1
tz.transition 2032, 3, :o9, 1962874800
-
1
tz.transition 2032, 11, :o8, 1983434400
-
1
tz.transition 2033, 3, :o9, 1994324400
-
1
tz.transition 2033, 11, :o8, 2014884000
-
1
tz.transition 2034, 3, :o9, 2025774000
-
1
tz.transition 2034, 11, :o8, 2046333600
-
1
tz.transition 2035, 3, :o9, 2057223600
-
1
tz.transition 2035, 11, :o8, 2077783200
-
1
tz.transition 2036, 3, :o9, 2088673200
-
1
tz.transition 2036, 11, :o8, 2109232800
-
1
tz.transition 2037, 3, :o9, 2120122800
-
1
tz.transition 2037, 11, :o8, 2140682400
-
1
tz.transition 2038, 3, :o9, 59171927, 24
-
1
tz.transition 2038, 11, :o8, 29588819, 12
-
1
tz.transition 2039, 3, :o9, 59180663, 24
-
1
tz.transition 2039, 11, :o8, 29593187, 12
-
1
tz.transition 2040, 3, :o9, 59189399, 24
-
1
tz.transition 2040, 11, :o8, 29597555, 12
-
1
tz.transition 2041, 3, :o9, 59198135, 24
-
1
tz.transition 2041, 11, :o8, 29601923, 12
-
1
tz.transition 2042, 3, :o9, 59206871, 24
-
1
tz.transition 2042, 11, :o8, 29606291, 12
-
1
tz.transition 2043, 3, :o9, 59215607, 24
-
1
tz.transition 2043, 11, :o8, 29610659, 12
-
1
tz.transition 2044, 3, :o9, 59224511, 24
-
1
tz.transition 2044, 11, :o8, 29615111, 12
-
1
tz.transition 2045, 3, :o9, 59233247, 24
-
1
tz.transition 2045, 11, :o8, 29619479, 12
-
1
tz.transition 2046, 3, :o9, 59241983, 24
-
1
tz.transition 2046, 11, :o8, 29623847, 12
-
1
tz.transition 2047, 3, :o9, 59250719, 24
-
1
tz.transition 2047, 11, :o8, 29628215, 12
-
1
tz.transition 2048, 3, :o9, 59259455, 24
-
1
tz.transition 2048, 11, :o8, 29632583, 12
-
1
tz.transition 2049, 3, :o9, 59268359, 24
-
1
tz.transition 2049, 11, :o8, 29637035, 12
-
1
tz.transition 2050, 3, :o9, 59277095, 24
-
1
tz.transition 2050, 11, :o8, 29641403, 12
-
end
-
end
-
end
-
end
-
end
-
1
module TZInfo
-
1
module Definitions
-
1
module America
-
1
module La_Paz
-
1
include TimezoneDefinition
-
-
1
timezone 'America/La_Paz' do |tz|
-
1
tz.offset :o0, -16356, 0, :LMT
-
1
tz.offset :o1, -16356, 0, :CMT
-
1
tz.offset :o2, -16356, 3600, :BOST
-
1
tz.offset :o3, -14400, 0, :BOT
-
-
1
tz.transition 1890, 1, :o1, 17361854563, 7200
-
1
tz.transition 1931, 10, :o2, 17471733763, 7200
-
1
tz.transition 1932, 3, :o3, 17472871063, 7200
-
end
-
end
-
end
-
end
-
end
-
1
module TZInfo
-
1
module Definitions
-
1
module America
-
1
module Lima
-
1
include TimezoneDefinition
-
-
1
timezone 'America/Lima' do |tz|
-
1
tz.offset :o0, -18492, 0, :LMT
-
1
tz.offset :o1, -18516, 0, :LMT
-
1
tz.offset :o2, -18000, 0, :PET
-
1
tz.offset :o3, -18000, 3600, :PEST
-
-
1
tz.transition 1890, 1, :o1, 17361854741, 7200
-
1
tz.transition 1908, 7, :o2, 17410685143, 7200
-
1
tz.transition 1938, 1, :o3, 58293593, 24
-
1
tz.transition 1938, 4, :o2, 7286969, 3
-
1
tz.transition 1938, 9, :o3, 58300001, 24
-
1
tz.transition 1939, 3, :o2, 7288046, 3
-
1
tz.transition 1939, 9, :o3, 58308737, 24
-
1
tz.transition 1940, 3, :o2, 7289138, 3
-
1
tz.transition 1986, 1, :o3, 504939600
-
1
tz.transition 1986, 4, :o2, 512712000
-
1
tz.transition 1987, 1, :o3, 536475600
-
1
tz.transition 1987, 4, :o2, 544248000
-
1
tz.transition 1990, 1, :o3, 631170000
-
1
tz.transition 1990, 4, :o2, 638942400
-
1
tz.transition 1994, 1, :o3, 757400400
-
1
tz.transition 1994, 4, :o2, 765172800
-
end
-
end
-
end
-
end
-
end
-
1
module TZInfo
-
1
module Definitions
-
1
module America
-
1
module Los_Angeles
-
1
include TimezoneDefinition
-
-
1
timezone 'America/Los_Angeles' do |tz|
-
1
tz.offset :o0, -28378, 0, :LMT
-
1
tz.offset :o1, -28800, 0, :PST
-
1
tz.offset :o2, -28800, 3600, :PDT
-
1
tz.offset :o3, -28800, 3600, :PWT
-
1
tz.offset :o4, -28800, 3600, :PPT
-
-
1
tz.transition 1883, 11, :o1, 7227400, 3
-
1
tz.transition 1918, 3, :o2, 29060207, 12
-
1
tz.transition 1918, 10, :o1, 19375151, 8
-
1
tz.transition 1919, 3, :o2, 29064575, 12
-
1
tz.transition 1919, 10, :o1, 19378063, 8
-
1
tz.transition 1942, 2, :o3, 29164799, 12
-
1
tz.transition 1945, 8, :o4, 58360379, 24
-
1
tz.transition 1945, 9, :o1, 19453831, 8
-
1
tz.transition 1948, 3, :o2, 29191499, 12
-
1
tz.transition 1949, 1, :o1, 19463343, 8
-
1
tz.transition 1950, 4, :o2, 29200823, 12
-
1
tz.transition 1950, 9, :o1, 19468391, 8
-
1
tz.transition 1951, 4, :o2, 29205191, 12
-
1
tz.transition 1951, 9, :o1, 19471359, 8
-
1
tz.transition 1952, 4, :o2, 29209559, 12
-
1
tz.transition 1952, 9, :o1, 19474271, 8
-
1
tz.transition 1953, 4, :o2, 29213927, 12
-
1
tz.transition 1953, 9, :o1, 19477183, 8
-
1
tz.transition 1954, 4, :o2, 29218295, 12
-
1
tz.transition 1954, 9, :o1, 19480095, 8
-
1
tz.transition 1955, 4, :o2, 29222663, 12
-
1
tz.transition 1955, 9, :o1, 19483007, 8
-
1
tz.transition 1956, 4, :o2, 29227115, 12
-
1
tz.transition 1956, 9, :o1, 19485975, 8
-
1
tz.transition 1957, 4, :o2, 29231483, 12
-
1
tz.transition 1957, 9, :o1, 19488887, 8
-
1
tz.transition 1958, 4, :o2, 29235851, 12
-
1
tz.transition 1958, 9, :o1, 19491799, 8
-
1
tz.transition 1959, 4, :o2, 29240219, 12
-
1
tz.transition 1959, 9, :o1, 19494711, 8
-
1
tz.transition 1960, 4, :o2, 29244587, 12
-
1
tz.transition 1960, 9, :o1, 19497623, 8
-
1
tz.transition 1961, 4, :o2, 29249039, 12
-
1
tz.transition 1961, 9, :o1, 19500535, 8
-
1
tz.transition 1962, 4, :o2, 29253407, 12
-
1
tz.transition 1962, 10, :o1, 19503727, 8
-
1
tz.transition 1963, 4, :o2, 29257775, 12
-
1
tz.transition 1963, 10, :o1, 19506639, 8
-
1
tz.transition 1964, 4, :o2, 29262143, 12
-
1
tz.transition 1964, 10, :o1, 19509551, 8
-
1
tz.transition 1965, 4, :o2, 29266511, 12
-
1
tz.transition 1965, 10, :o1, 19512519, 8
-
1
tz.transition 1966, 4, :o2, 29270879, 12
-
1
tz.transition 1966, 10, :o1, 19515431, 8
-
1
tz.transition 1967, 4, :o2, 29275331, 12
-
1
tz.transition 1967, 10, :o1, 19518343, 8
-
1
tz.transition 1968, 4, :o2, 29279699, 12
-
1
tz.transition 1968, 10, :o1, 19521255, 8
-
1
tz.transition 1969, 4, :o2, 29284067, 12
-
1
tz.transition 1969, 10, :o1, 19524167, 8
-
1
tz.transition 1970, 4, :o2, 9972000
-
1
tz.transition 1970, 10, :o1, 25693200
-
1
tz.transition 1971, 4, :o2, 41421600
-
1
tz.transition 1971, 10, :o1, 57747600
-
1
tz.transition 1972, 4, :o2, 73476000
-
1
tz.transition 1972, 10, :o1, 89197200
-
1
tz.transition 1973, 4, :o2, 104925600
-
1
tz.transition 1973, 10, :o1, 120646800
-
1
tz.transition 1974, 1, :o2, 126698400
-
1
tz.transition 1974, 10, :o1, 152096400
-
1
tz.transition 1975, 2, :o2, 162381600
-
1
tz.transition 1975, 10, :o1, 183546000
-
1
tz.transition 1976, 4, :o2, 199274400
-
1
tz.transition 1976, 10, :o1, 215600400
-
1
tz.transition 1977, 4, :o2, 230724000
-
1
tz.transition 1977, 10, :o1, 247050000
-
1
tz.transition 1978, 4, :o2, 262778400
-
1
tz.transition 1978, 10, :o1, 278499600
-
1
tz.transition 1979, 4, :o2, 294228000
-
1
tz.transition 1979, 10, :o1, 309949200
-
1
tz.transition 1980, 4, :o2, 325677600
-
1
tz.transition 1980, 10, :o1, 341398800
-
1
tz.transition 1981, 4, :o2, 357127200
-
1
tz.transition 1981, 10, :o1, 372848400
-
1
tz.transition 1982, 4, :o2, 388576800
-
1
tz.transition 1982, 10, :o1, 404902800
-
1
tz.transition 1983, 4, :o2, 420026400
-
1
tz.transition 1983, 10, :o1, 436352400
-
1
tz.transition 1984, 4, :o2, 452080800
-
1
tz.transition 1984, 10, :o1, 467802000
-
1
tz.transition 1985, 4, :o2, 483530400
-
1
tz.transition 1985, 10, :o1, 499251600
-
1
tz.transition 1986, 4, :o2, 514980000
-
1
tz.transition 1986, 10, :o1, 530701200
-
1
tz.transition 1987, 4, :o2, 544615200
-
1
tz.transition 1987, 10, :o1, 562150800
-
1
tz.transition 1988, 4, :o2, 576064800
-
1
tz.transition 1988, 10, :o1, 594205200
-
1
tz.transition 1989, 4, :o2, 607514400
-
1
tz.transition 1989, 10, :o1, 625654800
-
1
tz.transition 1990, 4, :o2, 638964000
-
1
tz.transition 1990, 10, :o1, 657104400
-
1
tz.transition 1991, 4, :o2, 671018400
-
1
tz.transition 1991, 10, :o1, 688554000
-
1
tz.transition 1992, 4, :o2, 702468000
-
1
tz.transition 1992, 10, :o1, 720003600
-
1
tz.transition 1993, 4, :o2, 733917600
-
1
tz.transition 1993, 10, :o1, 752058000
-
1
tz.transition 1994, 4, :o2, 765367200
-
1
tz.transition 1994, 10, :o1, 783507600
-
1
tz.transition 1995, 4, :o2, 796816800
-
1
tz.transition 1995, 10, :o1, 814957200
-
1
tz.transition 1996, 4, :o2, 828871200
-
1
tz.transition 1996, 10, :o1, 846406800
-
1
tz.transition 1997, 4, :o2, 860320800
-
1
tz.transition 1997, 10, :o1, 877856400
-
1
tz.transition 1998, 4, :o2, 891770400
-
1
tz.transition 1998, 10, :o1, 909306000
-
1
tz.transition 1999, 4, :o2, 923220000
-
1
tz.transition 1999, 10, :o1, 941360400
-
1
tz.transition 2000, 4, :o2, 954669600
-
1
tz.transition 2000, 10, :o1, 972810000
-
1
tz.transition 2001, 4, :o2, 986119200
-
1
tz.transition 2001, 10, :o1, 1004259600
-
1
tz.transition 2002, 4, :o2, 1018173600
-
1
tz.transition 2002, 10, :o1, 1035709200
-
1
tz.transition 2003, 4, :o2, 1049623200
-
1
tz.transition 2003, 10, :o1, 1067158800
-
1
tz.transition 2004, 4, :o2, 1081072800
-
1
tz.transition 2004, 10, :o1, 1099213200
-
1
tz.transition 2005, 4, :o2, 1112522400
-
1
tz.transition 2005, 10, :o1, 1130662800
-
1
tz.transition 2006, 4, :o2, 1143972000
-
1
tz.transition 2006, 10, :o1, 1162112400
-
1
tz.transition 2007, 3, :o2, 1173607200
-
1
tz.transition 2007, 11, :o1, 1194166800
-
1
tz.transition 2008, 3, :o2, 1205056800
-
1
tz.transition 2008, 11, :o1, 1225616400
-
1
tz.transition 2009, 3, :o2, 1236506400
-
1
tz.transition 2009, 11, :o1, 1257066000
-
1
tz.transition 2010, 3, :o2, 1268560800
-
1
tz.transition 2010, 11, :o1, 1289120400
-
1
tz.transition 2011, 3, :o2, 1300010400
-
1
tz.transition 2011, 11, :o1, 1320570000
-
1
tz.transition 2012, 3, :o2, 1331460000
-
1
tz.transition 2012, 11, :o1, 1352019600
-
1
tz.transition 2013, 3, :o2, 1362909600
-
1
tz.transition 2013, 11, :o1, 1383469200
-
1
tz.transition 2014, 3, :o2, 1394359200
-
1
tz.transition 2014, 11, :o1, 1414918800
-
1
tz.transition 2015, 3, :o2, 1425808800
-
1
tz.transition 2015, 11, :o1, 1446368400
-
1
tz.transition 2016, 3, :o2, 1457863200
-
1
tz.transition 2016, 11, :o1, 1478422800
-
1
tz.transition 2017, 3, :o2, 1489312800
-
1
tz.transition 2017, 11, :o1, 1509872400
-
1
tz.transition 2018, 3, :o2, 1520762400
-
1
tz.transition 2018, 11, :o1, 1541322000
-
1
tz.transition 2019, 3, :o2, 1552212000
-
1
tz.transition 2019, 11, :o1, 1572771600
-
1
tz.transition 2020, 3, :o2, 1583661600
-
1
tz.transition 2020, 11, :o1, 1604221200
-
1
tz.transition 2021, 3, :o2, 1615716000
-
1
tz.transition 2021, 11, :o1, 1636275600
-
1
tz.transition 2022, 3, :o2, 1647165600
-
1
tz.transition 2022, 11, :o1, 1667725200
-
1
tz.transition 2023, 3, :o2, 1678615200
-
1
tz.transition 2023, 11, :o1, 1699174800
-
1
tz.transition 2024, 3, :o2, 1710064800
-
1
tz.transition 2024, 11, :o1, 1730624400
-
1
tz.transition 2025, 3, :o2, 1741514400
-
1
tz.transition 2025, 11, :o1, 1762074000
-
1
tz.transition 2026, 3, :o2, 1772964000
-
1
tz.transition 2026, 11, :o1, 1793523600
-
1
tz.transition 2027, 3, :o2, 1805018400
-
1
tz.transition 2027, 11, :o1, 1825578000
-
1
tz.transition 2028, 3, :o2, 1836468000
-
1
tz.transition 2028, 11, :o1, 1857027600
-
1
tz.transition 2029, 3, :o2, 1867917600
-
1
tz.transition 2029, 11, :o1, 1888477200
-
1
tz.transition 2030, 3, :o2, 1899367200
-
1
tz.transition 2030, 11, :o1, 1919926800
-
1
tz.transition 2031, 3, :o2, 1930816800
-
1
tz.transition 2031, 11, :o1, 1951376400
-
1
tz.transition 2032, 3, :o2, 1962871200
-
1
tz.transition 2032, 11, :o1, 1983430800
-
1
tz.transition 2033, 3, :o2, 1994320800
-
1
tz.transition 2033, 11, :o1, 2014880400
-
1
tz.transition 2034, 3, :o2, 2025770400
-
1
tz.transition 2034, 11, :o1, 2046330000
-
1
tz.transition 2035, 3, :o2, 2057220000
-
1
tz.transition 2035, 11, :o1, 2077779600
-
1
tz.transition 2036, 3, :o2, 2088669600
-
1
tz.transition 2036, 11, :o1, 2109229200
-
1
tz.transition 2037, 3, :o2, 2120119200
-
1
tz.transition 2037, 11, :o1, 2140678800
-
1
tz.transition 2038, 3, :o2, 29585963, 12
-
1
tz.transition 2038, 11, :o1, 19725879, 8
-
1
tz.transition 2039, 3, :o2, 29590331, 12
-
1
tz.transition 2039, 11, :o1, 19728791, 8
-
1
tz.transition 2040, 3, :o2, 29594699, 12
-
1
tz.transition 2040, 11, :o1, 19731703, 8
-
1
tz.transition 2041, 3, :o2, 29599067, 12
-
1
tz.transition 2041, 11, :o1, 19734615, 8
-
1
tz.transition 2042, 3, :o2, 29603435, 12
-
1
tz.transition 2042, 11, :o1, 19737527, 8
-
1
tz.transition 2043, 3, :o2, 29607803, 12
-
1
tz.transition 2043, 11, :o1, 19740439, 8
-
1
tz.transition 2044, 3, :o2, 29612255, 12
-
1
tz.transition 2044, 11, :o1, 19743407, 8
-
1
tz.transition 2045, 3, :o2, 29616623, 12
-
1
tz.transition 2045, 11, :o1, 19746319, 8
-
1
tz.transition 2046, 3, :o2, 29620991, 12
-
1
tz.transition 2046, 11, :o1, 19749231, 8
-
1
tz.transition 2047, 3, :o2, 29625359, 12
-
1
tz.transition 2047, 11, :o1, 19752143, 8
-
1
tz.transition 2048, 3, :o2, 29629727, 12
-
1
tz.transition 2048, 11, :o1, 19755055, 8
-
1
tz.transition 2049, 3, :o2, 29634179, 12
-
1
tz.transition 2049, 11, :o1, 19758023, 8
-
1
tz.transition 2050, 3, :o2, 29638547, 12
-
1
tz.transition 2050, 11, :o1, 19760935, 8
-
end
-
end
-
end
-
end
-
end
-
1
module TZInfo
-
1
module Definitions
-
1
module America
-
1
module Mazatlan
-
1
include TimezoneDefinition
-
-
1
timezone 'America/Mazatlan' do |tz|
-
1
tz.offset :o0, -25540, 0, :LMT
-
1
tz.offset :o1, -25200, 0, :MST
-
1
tz.offset :o2, -21600, 0, :CST
-
1
tz.offset :o3, -28800, 0, :PST
-
1
tz.offset :o4, -25200, 3600, :MDT
-
-
1
tz.transition 1922, 1, :o1, 58153339, 24
-
1
tz.transition 1927, 6, :o2, 9700171, 4
-
1
tz.transition 1930, 11, :o1, 9705183, 4
-
1
tz.transition 1931, 5, :o2, 9705855, 4
-
1
tz.transition 1931, 10, :o1, 9706463, 4
-
1
tz.transition 1932, 4, :o2, 58243171, 24
-
1
tz.transition 1942, 4, :o1, 9721895, 4
-
1
tz.transition 1949, 1, :o3, 58390339, 24
-
1
tz.transition 1970, 1, :o1, 28800
-
1
tz.transition 1996, 4, :o4, 828867600
-
1
tz.transition 1996, 10, :o1, 846403200
-
1
tz.transition 1997, 4, :o4, 860317200
-
1
tz.transition 1997, 10, :o1, 877852800
-
1
tz.transition 1998, 4, :o4, 891766800
-
1
tz.transition 1998, 10, :o1, 909302400
-
1
tz.transition 1999, 4, :o4, 923216400
-
1
tz.transition 1999, 10, :o1, 941356800
-
1
tz.transition 2000, 4, :o4, 954666000
-
1
tz.transition 2000, 10, :o1, 972806400
-
1
tz.transition 2001, 5, :o4, 989139600
-
1
tz.transition 2001, 9, :o1, 1001836800
-
1
tz.transition 2002, 4, :o4, 1018170000
-
1
tz.transition 2002, 10, :o1, 1035705600
-
1
tz.transition 2003, 4, :o4, 1049619600
-
1
tz.transition 2003, 10, :o1, 1067155200
-
1
tz.transition 2004, 4, :o4, 1081069200
-
1
tz.transition 2004, 10, :o1, 1099209600
-
1
tz.transition 2005, 4, :o4, 1112518800
-
1
tz.transition 2005, 10, :o1, 1130659200
-
1
tz.transition 2006, 4, :o4, 1143968400
-
1
tz.transition 2006, 10, :o1, 1162108800
-
1
tz.transition 2007, 4, :o4, 1175418000
-
1
tz.transition 2007, 10, :o1, 1193558400
-
1
tz.transition 2008, 4, :o4, 1207472400
-
1
tz.transition 2008, 10, :o1, 1225008000
-
1
tz.transition 2009, 4, :o4, 1238922000
-
1
tz.transition 2009, 10, :o1, 1256457600
-
1
tz.transition 2010, 4, :o4, 1270371600
-
1
tz.transition 2010, 10, :o1, 1288512000
-
1
tz.transition 2011, 4, :o4, 1301821200
-
1
tz.transition 2011, 10, :o1, 1319961600
-
1
tz.transition 2012, 4, :o4, 1333270800
-
1
tz.transition 2012, 10, :o1, 1351411200
-
1
tz.transition 2013, 4, :o4, 1365325200
-
1
tz.transition 2013, 10, :o1, 1382860800
-
1
tz.transition 2014, 4, :o4, 1396774800
-
1
tz.transition 2014, 10, :o1, 1414310400
-
1
tz.transition 2015, 4, :o4, 1428224400
-
1
tz.transition 2015, 10, :o1, 1445760000
-
1
tz.transition 2016, 4, :o4, 1459674000
-
1
tz.transition 2016, 10, :o1, 1477814400
-
1
tz.transition 2017, 4, :o4, 1491123600
-
1
tz.transition 2017, 10, :o1, 1509264000
-
1
tz.transition 2018, 4, :o4, 1522573200
-
1
tz.transition 2018, 10, :o1, 1540713600
-
1
tz.transition 2019, 4, :o4, 1554627600
-
1
tz.transition 2019, 10, :o1, 1572163200
-
1
tz.transition 2020, 4, :o4, 1586077200
-
1
tz.transition 2020, 10, :o1, 1603612800
-
1
tz.transition 2021, 4, :o4, 1617526800
-
1
tz.transition 2021, 10, :o1, 1635667200
-
1
tz.transition 2022, 4, :o4, 1648976400
-
1
tz.transition 2022, 10, :o1, 1667116800
-
1
tz.transition 2023, 4, :o4, 1680426000
-
1
tz.transition 2023, 10, :o1, 1698566400
-
1
tz.transition 2024, 4, :o4, 1712480400
-
1
tz.transition 2024, 10, :o1, 1730016000
-
1
tz.transition 2025, 4, :o4, 1743930000
-
1
tz.transition 2025, 10, :o1, 1761465600
-
1
tz.transition 2026, 4, :o4, 1775379600
-
1
tz.transition 2026, 10, :o1, 1792915200
-
1
tz.transition 2027, 4, :o4, 1806829200
-
1
tz.transition 2027, 10, :o1, 1824969600
-
1
tz.transition 2028, 4, :o4, 1838278800
-
1
tz.transition 2028, 10, :o1, 1856419200
-
1
tz.transition 2029, 4, :o4, 1869728400
-
1
tz.transition 2029, 10, :o1, 1887868800
-
1
tz.transition 2030, 4, :o4, 1901782800
-
1
tz.transition 2030, 10, :o1, 1919318400
-
1
tz.transition 2031, 4, :o4, 1933232400
-
1
tz.transition 2031, 10, :o1, 1950768000
-
1
tz.transition 2032, 4, :o4, 1964682000
-
1
tz.transition 2032, 10, :o1, 1982822400
-
1
tz.transition 2033, 4, :o4, 1996131600
-
1
tz.transition 2033, 10, :o1, 2014272000
-
1
tz.transition 2034, 4, :o4, 2027581200
-
1
tz.transition 2034, 10, :o1, 2045721600
-
1
tz.transition 2035, 4, :o4, 2059030800
-
1
tz.transition 2035, 10, :o1, 2077171200
-
1
tz.transition 2036, 4, :o4, 2091085200
-
1
tz.transition 2036, 10, :o1, 2108620800
-
1
tz.transition 2037, 4, :o4, 2122534800
-
1
tz.transition 2037, 10, :o1, 2140070400
-
1
tz.transition 2038, 4, :o4, 19724143, 8
-
1
tz.transition 2038, 10, :o1, 14794367, 6
-
1
tz.transition 2039, 4, :o4, 19727055, 8
-
1
tz.transition 2039, 10, :o1, 14796551, 6
-
1
tz.transition 2040, 4, :o4, 19729967, 8
-
1
tz.transition 2040, 10, :o1, 14798735, 6
-
1
tz.transition 2041, 4, :o4, 19732935, 8
-
1
tz.transition 2041, 10, :o1, 14800919, 6
-
1
tz.transition 2042, 4, :o4, 19735847, 8
-
1
tz.transition 2042, 10, :o1, 14803103, 6
-
1
tz.transition 2043, 4, :o4, 19738759, 8
-
1
tz.transition 2043, 10, :o1, 14805287, 6
-
1
tz.transition 2044, 4, :o4, 19741671, 8
-
1
tz.transition 2044, 10, :o1, 14807513, 6
-
1
tz.transition 2045, 4, :o4, 19744583, 8
-
1
tz.transition 2045, 10, :o1, 14809697, 6
-
1
tz.transition 2046, 4, :o4, 19747495, 8
-
1
tz.transition 2046, 10, :o1, 14811881, 6
-
1
tz.transition 2047, 4, :o4, 19750463, 8
-
1
tz.transition 2047, 10, :o1, 14814065, 6
-
1
tz.transition 2048, 4, :o4, 19753375, 8
-
1
tz.transition 2048, 10, :o1, 14816249, 6
-
1
tz.transition 2049, 4, :o4, 19756287, 8
-
1
tz.transition 2049, 10, :o1, 14818475, 6
-
1
tz.transition 2050, 4, :o4, 19759199, 8
-
1
tz.transition 2050, 10, :o1, 14820659, 6
-
end
-
end
-
end
-
end
-
end
-
1
module TZInfo
-
1
module Definitions
-
1
module America
-
1
module Mexico_City
-
1
include TimezoneDefinition
-
-
1
timezone 'America/Mexico_City' do |tz|
-
1
tz.offset :o0, -23796, 0, :LMT
-
1
tz.offset :o1, -25200, 0, :MST
-
1
tz.offset :o2, -21600, 0, :CST
-
1
tz.offset :o3, -21600, 3600, :CDT
-
1
tz.offset :o4, -21600, 3600, :CWT
-
-
1
tz.transition 1922, 1, :o1, 58153339, 24
-
1
tz.transition 1927, 6, :o2, 9700171, 4
-
1
tz.transition 1930, 11, :o1, 9705183, 4
-
1
tz.transition 1931, 5, :o2, 9705855, 4
-
1
tz.transition 1931, 10, :o1, 9706463, 4
-
1
tz.transition 1932, 4, :o2, 58243171, 24
-
1
tz.transition 1939, 2, :o3, 9717199, 4
-
1
tz.transition 1939, 6, :o2, 58306553, 24
-
1
tz.transition 1940, 12, :o3, 9719891, 4
-
1
tz.transition 1941, 4, :o2, 58322057, 24
-
1
tz.transition 1943, 12, :o4, 9724299, 4
-
1
tz.transition 1944, 5, :o2, 58349081, 24
-
1
tz.transition 1950, 2, :o3, 9733299, 4
-
1
tz.transition 1950, 7, :o2, 58403825, 24
-
1
tz.transition 1996, 4, :o3, 828864000
-
1
tz.transition 1996, 10, :o2, 846399600
-
1
tz.transition 1997, 4, :o3, 860313600
-
1
tz.transition 1997, 10, :o2, 877849200
-
1
tz.transition 1998, 4, :o3, 891763200
-
1
tz.transition 1998, 10, :o2, 909298800
-
1
tz.transition 1999, 4, :o3, 923212800
-
1
tz.transition 1999, 10, :o2, 941353200
-
1
tz.transition 2000, 4, :o3, 954662400
-
1
tz.transition 2000, 10, :o2, 972802800
-
1
tz.transition 2001, 5, :o3, 989136000
-
1
tz.transition 2001, 9, :o2, 1001833200
-
1
tz.transition 2002, 4, :o3, 1018166400
-
1
tz.transition 2002, 10, :o2, 1035702000
-
1
tz.transition 2003, 4, :o3, 1049616000
-
1
tz.transition 2003, 10, :o2, 1067151600
-
1
tz.transition 2004, 4, :o3, 1081065600
-
1
tz.transition 2004, 10, :o2, 1099206000
-
1
tz.transition 2005, 4, :o3, 1112515200
-
1
tz.transition 2005, 10, :o2, 1130655600
-
1
tz.transition 2006, 4, :o3, 1143964800
-
1
tz.transition 2006, 10, :o2, 1162105200
-
1
tz.transition 2007, 4, :o3, 1175414400
-
1
tz.transition 2007, 10, :o2, 1193554800
-
1
tz.transition 2008, 4, :o3, 1207468800
-
1
tz.transition 2008, 10, :o2, 1225004400
-
1
tz.transition 2009, 4, :o3, 1238918400
-
1
tz.transition 2009, 10, :o2, 1256454000
-
1
tz.transition 2010, 4, :o3, 1270368000
-
1
tz.transition 2010, 10, :o2, 1288508400
-
1
tz.transition 2011, 4, :o3, 1301817600
-
1
tz.transition 2011, 10, :o2, 1319958000
-
1
tz.transition 2012, 4, :o3, 1333267200
-
1
tz.transition 2012, 10, :o2, 1351407600
-
1
tz.transition 2013, 4, :o3, 1365321600
-
1
tz.transition 2013, 10, :o2, 1382857200
-
1
tz.transition 2014, 4, :o3, 1396771200
-
1
tz.transition 2014, 10, :o2, 1414306800
-
1
tz.transition 2015, 4, :o3, 1428220800
-
1
tz.transition 2015, 10, :o2, 1445756400
-
1
tz.transition 2016, 4, :o3, 1459670400
-
1
tz.transition 2016, 10, :o2, 1477810800
-
1
tz.transition 2017, 4, :o3, 1491120000
-
1
tz.transition 2017, 10, :o2, 1509260400
-
1
tz.transition 2018, 4, :o3, 1522569600
-
1
tz.transition 2018, 10, :o2, 1540710000
-
1
tz.transition 2019, 4, :o3, 1554624000
-
1
tz.transition 2019, 10, :o2, 1572159600
-
1
tz.transition 2020, 4, :o3, 1586073600
-
1
tz.transition 2020, 10, :o2, 1603609200
-
1
tz.transition 2021, 4, :o3, 1617523200
-
1
tz.transition 2021, 10, :o2, 1635663600
-
1
tz.transition 2022, 4, :o3, 1648972800
-
1
tz.transition 2022, 10, :o2, 1667113200
-
1
tz.transition 2023, 4, :o3, 1680422400
-
1
tz.transition 2023, 10, :o2, 1698562800
-
1
tz.transition 2024, 4, :o3, 1712476800
-
1
tz.transition 2024, 10, :o2, 1730012400
-
1
tz.transition 2025, 4, :o3, 1743926400
-
1
tz.transition 2025, 10, :o2, 1761462000
-
1
tz.transition 2026, 4, :o3, 1775376000
-
1
tz.transition 2026, 10, :o2, 1792911600
-
1
tz.transition 2027, 4, :o3, 1806825600
-
1
tz.transition 2027, 10, :o2, 1824966000
-
1
tz.transition 2028, 4, :o3, 1838275200
-
1
tz.transition 2028, 10, :o2, 1856415600
-
1
tz.transition 2029, 4, :o3, 1869724800
-
1
tz.transition 2029, 10, :o2, 1887865200
-
1
tz.transition 2030, 4, :o3, 1901779200
-
1
tz.transition 2030, 10, :o2, 1919314800
-
1
tz.transition 2031, 4, :o3, 1933228800
-
1
tz.transition 2031, 10, :o2, 1950764400
-
1
tz.transition 2032, 4, :o3, 1964678400
-
1
tz.transition 2032, 10, :o2, 1982818800
-
1
tz.transition 2033, 4, :o3, 1996128000
-
1
tz.transition 2033, 10, :o2, 2014268400
-
1
tz.transition 2034, 4, :o3, 2027577600
-
1
tz.transition 2034, 10, :o2, 2045718000
-
1
tz.transition 2035, 4, :o3, 2059027200
-
1
tz.transition 2035, 10, :o2, 2077167600
-
1
tz.transition 2036, 4, :o3, 2091081600
-
1
tz.transition 2036, 10, :o2, 2108617200
-
1
tz.transition 2037, 4, :o3, 2122531200
-
1
tz.transition 2037, 10, :o2, 2140066800
-
1
tz.transition 2038, 4, :o3, 14793107, 6
-
1
tz.transition 2038, 10, :o2, 59177467, 24
-
1
tz.transition 2039, 4, :o3, 14795291, 6
-
1
tz.transition 2039, 10, :o2, 59186203, 24
-
1
tz.transition 2040, 4, :o3, 14797475, 6
-
1
tz.transition 2040, 10, :o2, 59194939, 24
-
1
tz.transition 2041, 4, :o3, 14799701, 6
-
1
tz.transition 2041, 10, :o2, 59203675, 24
-
1
tz.transition 2042, 4, :o3, 14801885, 6
-
1
tz.transition 2042, 10, :o2, 59212411, 24
-
1
tz.transition 2043, 4, :o3, 14804069, 6
-
1
tz.transition 2043, 10, :o2, 59221147, 24
-
1
tz.transition 2044, 4, :o3, 14806253, 6
-
1
tz.transition 2044, 10, :o2, 59230051, 24
-
1
tz.transition 2045, 4, :o3, 14808437, 6
-
1
tz.transition 2045, 10, :o2, 59238787, 24
-
1
tz.transition 2046, 4, :o3, 14810621, 6
-
1
tz.transition 2046, 10, :o2, 59247523, 24
-
1
tz.transition 2047, 4, :o3, 14812847, 6
-
1
tz.transition 2047, 10, :o2, 59256259, 24
-
1
tz.transition 2048, 4, :o3, 14815031, 6
-
1
tz.transition 2048, 10, :o2, 59264995, 24
-
1
tz.transition 2049, 4, :o3, 14817215, 6
-
1
tz.transition 2049, 10, :o2, 59273899, 24
-
1
tz.transition 2050, 4, :o3, 14819399, 6
-
1
tz.transition 2050, 10, :o2, 59282635, 24
-
end
-
end
-
end
-
end
-
end
-
1
module TZInfo
-
1
module Definitions
-
1
module America
-
1
module Monterrey
-
1
include TimezoneDefinition
-
-
1
timezone 'America/Monterrey' do |tz|
-
1
tz.offset :o0, -24076, 0, :LMT
-
1
tz.offset :o1, -21600, 0, :CST
-
1
tz.offset :o2, -21600, 3600, :CDT
-
-
1
tz.transition 1922, 1, :o1, 9692223, 4
-
1
tz.transition 1988, 4, :o2, 576057600
-
1
tz.transition 1988, 10, :o1, 594198000
-
1
tz.transition 1996, 4, :o2, 828864000
-
1
tz.transition 1996, 10, :o1, 846399600
-
1
tz.transition 1997, 4, :o2, 860313600
-
1
tz.transition 1997, 10, :o1, 877849200
-
1
tz.transition 1998, 4, :o2, 891763200
-
1
tz.transition 1998, 10, :o1, 909298800
-
1
tz.transition 1999, 4, :o2, 923212800
-
1
tz.transition 1999, 10, :o1, 941353200
-
1
tz.transition 2000, 4, :o2, 954662400
-
1
tz.transition 2000, 10, :o1, 972802800
-
1
tz.transition 2001, 5, :o2, 989136000
-
1
tz.transition 2001, 9, :o1, 1001833200
-
1
tz.transition 2002, 4, :o2, 1018166400
-
1
tz.transition 2002, 10, :o1, 1035702000
-
1
tz.transition 2003, 4, :o2, 1049616000
-
1
tz.transition 2003, 10, :o1, 1067151600
-
1
tz.transition 2004, 4, :o2, 1081065600
-
1
tz.transition 2004, 10, :o1, 1099206000
-
1
tz.transition 2005, 4, :o2, 1112515200
-
1
tz.transition 2005, 10, :o1, 1130655600
-
1
tz.transition 2006, 4, :o2, 1143964800
-
1
tz.transition 2006, 10, :o1, 1162105200
-
1
tz.transition 2007, 4, :o2, 1175414400
-
1
tz.transition 2007, 10, :o1, 1193554800
-
1
tz.transition 2008, 4, :o2, 1207468800
-
1
tz.transition 2008, 10, :o1, 1225004400
-
1
tz.transition 2009, 4, :o2, 1238918400
-
1
tz.transition 2009, 10, :o1, 1256454000
-
1
tz.transition 2010, 4, :o2, 1270368000
-
1
tz.transition 2010, 10, :o1, 1288508400
-
1
tz.transition 2011, 4, :o2, 1301817600
-
1
tz.transition 2011, 10, :o1, 1319958000
-
1
tz.transition 2012, 4, :o2, 1333267200
-
1
tz.transition 2012, 10, :o1, 1351407600
-
1
tz.transition 2013, 4, :o2, 1365321600
-
1
tz.transition 2013, 10, :o1, 1382857200
-
1
tz.transition 2014, 4, :o2, 1396771200
-
1
tz.transition 2014, 10, :o1, 1414306800
-
1
tz.transition 2015, 4, :o2, 1428220800
-
1
tz.transition 2015, 10, :o1, 1445756400
-
1
tz.transition 2016, 4, :o2, 1459670400
-
1
tz.transition 2016, 10, :o1, 1477810800
-
1
tz.transition 2017, 4, :o2, 1491120000
-
1
tz.transition 2017, 10, :o1, 1509260400
-
1
tz.transition 2018, 4, :o2, 1522569600
-
1
tz.transition 2018, 10, :o1, 1540710000
-
1
tz.transition 2019, 4, :o2, 1554624000
-
1
tz.transition 2019, 10, :o1, 1572159600
-
1
tz.transition 2020, 4, :o2, 1586073600
-
1
tz.transition 2020, 10, :o1, 1603609200
-
1
tz.transition 2021, 4, :o2, 1617523200
-
1
tz.transition 2021, 10, :o1, 1635663600
-
1
tz.transition 2022, 4, :o2, 1648972800
-
1
tz.transition 2022, 10, :o1, 1667113200
-
1
tz.transition 2023, 4, :o2, 1680422400
-
1
tz.transition 2023, 10, :o1, 1698562800
-
1
tz.transition 2024, 4, :o2, 1712476800
-
1
tz.transition 2024, 10, :o1, 1730012400
-
1
tz.transition 2025, 4, :o2, 1743926400
-
1
tz.transition 2025, 10, :o1, 1761462000
-
1
tz.transition 2026, 4, :o2, 1775376000
-
1
tz.transition 2026, 10, :o1, 1792911600
-
1
tz.transition 2027, 4, :o2, 1806825600
-
1
tz.transition 2027, 10, :o1, 1824966000
-
1
tz.transition 2028, 4, :o2, 1838275200
-
1
tz.transition 2028, 10, :o1, 1856415600
-
1
tz.transition 2029, 4, :o2, 1869724800
-
1
tz.transition 2029, 10, :o1, 1887865200
-
1
tz.transition 2030, 4, :o2, 1901779200
-
1
tz.transition 2030, 10, :o1, 1919314800
-
1
tz.transition 2031, 4, :o2, 1933228800
-
1
tz.transition 2031, 10, :o1, 1950764400
-
1
tz.transition 2032, 4, :o2, 1964678400
-
1
tz.transition 2032, 10, :o1, 1982818800
-
1
tz.transition 2033, 4, :o2, 1996128000
-
1
tz.transition 2033, 10, :o1, 2014268400
-
1
tz.transition 2034, 4, :o2, 2027577600
-
1
tz.transition 2034, 10, :o1, 2045718000
-
1
tz.transition 2035, 4, :o2, 2059027200
-
1
tz.transition 2035, 10, :o1, 2077167600
-
1
tz.transition 2036, 4, :o2, 2091081600
-
1
tz.transition 2036, 10, :o1, 2108617200
-
1
tz.transition 2037, 4, :o2, 2122531200
-
1
tz.transition 2037, 10, :o1, 2140066800
-
1
tz.transition 2038, 4, :o2, 14793107, 6
-
1
tz.transition 2038, 10, :o1, 59177467, 24
-
1
tz.transition 2039, 4, :o2, 14795291, 6
-
1
tz.transition 2039, 10, :o1, 59186203, 24
-
1
tz.transition 2040, 4, :o2, 14797475, 6
-
1
tz.transition 2040, 10, :o1, 59194939, 24
-
1
tz.transition 2041, 4, :o2, 14799701, 6
-
1
tz.transition 2041, 10, :o1, 59203675, 24
-
1
tz.transition 2042, 4, :o2, 14801885, 6
-
1
tz.transition 2042, 10, :o1, 59212411, 24
-
1
tz.transition 2043, 4, :o2, 14804069, 6
-
1
tz.transition 2043, 10, :o1, 59221147, 24
-
1
tz.transition 2044, 4, :o2, 14806253, 6
-
1
tz.transition 2044, 10, :o1, 59230051, 24
-
1
tz.transition 2045, 4, :o2, 14808437, 6
-
1
tz.transition 2045, 10, :o1, 59238787, 24
-
1
tz.transition 2046, 4, :o2, 14810621, 6
-
1
tz.transition 2046, 10, :o1, 59247523, 24
-
1
tz.transition 2047, 4, :o2, 14812847, 6
-
1
tz.transition 2047, 10, :o1, 59256259, 24
-
1
tz.transition 2048, 4, :o2, 14815031, 6
-
1
tz.transition 2048, 10, :o1, 59264995, 24
-
1
tz.transition 2049, 4, :o2, 14817215, 6
-
1
tz.transition 2049, 10, :o1, 59273899, 24
-
1
tz.transition 2050, 4, :o2, 14819399, 6
-
1
tz.transition 2050, 10, :o1, 59282635, 24
-
end
-
end
-
end
-
end
-
end
-
1
module TZInfo
-
1
module Definitions
-
1
module America
-
1
module New_York
-
1
include TimezoneDefinition
-
-
1
timezone 'America/New_York' do |tz|
-
1
tz.offset :o0, -17762, 0, :LMT
-
1
tz.offset :o1, -18000, 0, :EST
-
1
tz.offset :o2, -18000, 3600, :EDT
-
1
tz.offset :o3, -18000, 3600, :EWT
-
1
tz.offset :o4, -18000, 3600, :EPT
-
-
1
tz.transition 1883, 11, :o1, 57819197, 24
-
1
tz.transition 1918, 3, :o2, 58120411, 24
-
1
tz.transition 1918, 10, :o1, 9687575, 4
-
1
tz.transition 1919, 3, :o2, 58129147, 24
-
1
tz.transition 1919, 10, :o1, 9689031, 4
-
1
tz.transition 1920, 3, :o2, 58137883, 24
-
1
tz.transition 1920, 10, :o1, 9690515, 4
-
1
tz.transition 1921, 4, :o2, 58147291, 24
-
1
tz.transition 1921, 9, :o1, 9691831, 4
-
1
tz.transition 1922, 4, :o2, 58156195, 24
-
1
tz.transition 1922, 9, :o1, 9693287, 4
-
1
tz.transition 1923, 4, :o2, 58164931, 24
-
1
tz.transition 1923, 9, :o1, 9694771, 4
-
1
tz.transition 1924, 4, :o2, 58173667, 24
-
1
tz.transition 1924, 9, :o1, 9696227, 4
-
1
tz.transition 1925, 4, :o2, 58182403, 24
-
1
tz.transition 1925, 9, :o1, 9697683, 4
-
1
tz.transition 1926, 4, :o2, 58191139, 24
-
1
tz.transition 1926, 9, :o1, 9699139, 4
-
1
tz.transition 1927, 4, :o2, 58199875, 24
-
1
tz.transition 1927, 9, :o1, 9700595, 4
-
1
tz.transition 1928, 4, :o2, 58208779, 24
-
1
tz.transition 1928, 9, :o1, 9702079, 4
-
1
tz.transition 1929, 4, :o2, 58217515, 24
-
1
tz.transition 1929, 9, :o1, 9703535, 4
-
1
tz.transition 1930, 4, :o2, 58226251, 24
-
1
tz.transition 1930, 9, :o1, 9704991, 4
-
1
tz.transition 1931, 4, :o2, 58234987, 24
-
1
tz.transition 1931, 9, :o1, 9706447, 4
-
1
tz.transition 1932, 4, :o2, 58243723, 24
-
1
tz.transition 1932, 9, :o1, 9707903, 4
-
1
tz.transition 1933, 4, :o2, 58252627, 24
-
1
tz.transition 1933, 9, :o1, 9709359, 4
-
1
tz.transition 1934, 4, :o2, 58261363, 24
-
1
tz.transition 1934, 9, :o1, 9710843, 4
-
1
tz.transition 1935, 4, :o2, 58270099, 24
-
1
tz.transition 1935, 9, :o1, 9712299, 4
-
1
tz.transition 1936, 4, :o2, 58278835, 24
-
1
tz.transition 1936, 9, :o1, 9713755, 4
-
1
tz.transition 1937, 4, :o2, 58287571, 24
-
1
tz.transition 1937, 9, :o1, 9715211, 4
-
1
tz.transition 1938, 4, :o2, 58296307, 24
-
1
tz.transition 1938, 9, :o1, 9716667, 4
-
1
tz.transition 1939, 4, :o2, 58305211, 24
-
1
tz.transition 1939, 9, :o1, 9718123, 4
-
1
tz.transition 1940, 4, :o2, 58313947, 24
-
1
tz.transition 1940, 9, :o1, 9719607, 4
-
1
tz.transition 1941, 4, :o2, 58322683, 24
-
1
tz.transition 1941, 9, :o1, 9721063, 4
-
1
tz.transition 1942, 2, :o3, 58329595, 24
-
1
tz.transition 1945, 8, :o4, 58360379, 24
-
1
tz.transition 1945, 9, :o1, 9726915, 4
-
1
tz.transition 1946, 4, :o2, 58366531, 24
-
1
tz.transition 1946, 9, :o1, 9728371, 4
-
1
tz.transition 1947, 4, :o2, 58375267, 24
-
1
tz.transition 1947, 9, :o1, 9729827, 4
-
1
tz.transition 1948, 4, :o2, 58384003, 24
-
1
tz.transition 1948, 9, :o1, 9731283, 4
-
1
tz.transition 1949, 4, :o2, 58392739, 24
-
1
tz.transition 1949, 9, :o1, 9732739, 4
-
1
tz.transition 1950, 4, :o2, 58401643, 24
-
1
tz.transition 1950, 9, :o1, 9734195, 4
-
1
tz.transition 1951, 4, :o2, 58410379, 24
-
1
tz.transition 1951, 9, :o1, 9735679, 4
-
1
tz.transition 1952, 4, :o2, 58419115, 24
-
1
tz.transition 1952, 9, :o1, 9737135, 4
-
1
tz.transition 1953, 4, :o2, 58427851, 24
-
1
tz.transition 1953, 9, :o1, 9738591, 4
-
1
tz.transition 1954, 4, :o2, 58436587, 24
-
1
tz.transition 1954, 9, :o1, 9740047, 4
-
1
tz.transition 1955, 4, :o2, 58445323, 24
-
1
tz.transition 1955, 10, :o1, 9741643, 4
-
1
tz.transition 1956, 4, :o2, 58454227, 24
-
1
tz.transition 1956, 10, :o1, 9743099, 4
-
1
tz.transition 1957, 4, :o2, 58462963, 24
-
1
tz.transition 1957, 10, :o1, 9744555, 4
-
1
tz.transition 1958, 4, :o2, 58471699, 24
-
1
tz.transition 1958, 10, :o1, 9746011, 4
-
1
tz.transition 1959, 4, :o2, 58480435, 24
-
1
tz.transition 1959, 10, :o1, 9747467, 4
-
1
tz.transition 1960, 4, :o2, 58489171, 24
-
1
tz.transition 1960, 10, :o1, 9748951, 4
-
1
tz.transition 1961, 4, :o2, 58498075, 24
-
1
tz.transition 1961, 10, :o1, 9750407, 4
-
1
tz.transition 1962, 4, :o2, 58506811, 24
-
1
tz.transition 1962, 10, :o1, 9751863, 4
-
1
tz.transition 1963, 4, :o2, 58515547, 24
-
1
tz.transition 1963, 10, :o1, 9753319, 4
-
1
tz.transition 1964, 4, :o2, 58524283, 24
-
1
tz.transition 1964, 10, :o1, 9754775, 4
-
1
tz.transition 1965, 4, :o2, 58533019, 24
-
1
tz.transition 1965, 10, :o1, 9756259, 4
-
1
tz.transition 1966, 4, :o2, 58541755, 24
-
1
tz.transition 1966, 10, :o1, 9757715, 4
-
1
tz.transition 1967, 4, :o2, 58550659, 24
-
1
tz.transition 1967, 10, :o1, 9759171, 4
-
1
tz.transition 1968, 4, :o2, 58559395, 24
-
1
tz.transition 1968, 10, :o1, 9760627, 4
-
1
tz.transition 1969, 4, :o2, 58568131, 24
-
1
tz.transition 1969, 10, :o1, 9762083, 4
-
1
tz.transition 1970, 4, :o2, 9961200
-
1
tz.transition 1970, 10, :o1, 25682400
-
1
tz.transition 1971, 4, :o2, 41410800
-
1
tz.transition 1971, 10, :o1, 57736800
-
1
tz.transition 1972, 4, :o2, 73465200
-
1
tz.transition 1972, 10, :o1, 89186400
-
1
tz.transition 1973, 4, :o2, 104914800
-
1
tz.transition 1973, 10, :o1, 120636000
-
1
tz.transition 1974, 1, :o2, 126687600
-
1
tz.transition 1974, 10, :o1, 152085600
-
1
tz.transition 1975, 2, :o2, 162370800
-
1
tz.transition 1975, 10, :o1, 183535200
-
1
tz.transition 1976, 4, :o2, 199263600
-
1
tz.transition 1976, 10, :o1, 215589600
-
1
tz.transition 1977, 4, :o2, 230713200
-
1
tz.transition 1977, 10, :o1, 247039200
-
1
tz.transition 1978, 4, :o2, 262767600
-
1
tz.transition 1978, 10, :o1, 278488800
-
1
tz.transition 1979, 4, :o2, 294217200
-
1
tz.transition 1979, 10, :o1, 309938400
-
1
tz.transition 1980, 4, :o2, 325666800
-
1
tz.transition 1980, 10, :o1, 341388000
-
1
tz.transition 1981, 4, :o2, 357116400
-
1
tz.transition 1981, 10, :o1, 372837600
-
1
tz.transition 1982, 4, :o2, 388566000
-
1
tz.transition 1982, 10, :o1, 404892000
-
1
tz.transition 1983, 4, :o2, 420015600
-
1
tz.transition 1983, 10, :o1, 436341600
-
1
tz.transition 1984, 4, :o2, 452070000
-
1
tz.transition 1984, 10, :o1, 467791200
-
1
tz.transition 1985, 4, :o2, 483519600
-
1
tz.transition 1985, 10, :o1, 499240800
-
1
tz.transition 1986, 4, :o2, 514969200
-
1
tz.transition 1986, 10, :o1, 530690400
-
1
tz.transition 1987, 4, :o2, 544604400
-
1
tz.transition 1987, 10, :o1, 562140000
-
1
tz.transition 1988, 4, :o2, 576054000
-
1
tz.transition 1988, 10, :o1, 594194400
-
1
tz.transition 1989, 4, :o2, 607503600
-
1
tz.transition 1989, 10, :o1, 625644000
-
1
tz.transition 1990, 4, :o2, 638953200
-
1
tz.transition 1990, 10, :o1, 657093600
-
1
tz.transition 1991, 4, :o2, 671007600
-
1
tz.transition 1991, 10, :o1, 688543200
-
1
tz.transition 1992, 4, :o2, 702457200
-
1
tz.transition 1992, 10, :o1, 719992800
-
1
tz.transition 1993, 4, :o2, 733906800
-
1
tz.transition 1993, 10, :o1, 752047200
-
1
tz.transition 1994, 4, :o2, 765356400
-
1
tz.transition 1994, 10, :o1, 783496800
-
1
tz.transition 1995, 4, :o2, 796806000
-
1
tz.transition 1995, 10, :o1, 814946400
-
1
tz.transition 1996, 4, :o2, 828860400
-
1
tz.transition 1996, 10, :o1, 846396000
-
1
tz.transition 1997, 4, :o2, 860310000
-
1
tz.transition 1997, 10, :o1, 877845600
-
1
tz.transition 1998, 4, :o2, 891759600
-
1
tz.transition 1998, 10, :o1, 909295200
-
1
tz.transition 1999, 4, :o2, 923209200
-
1
tz.transition 1999, 10, :o1, 941349600
-
1
tz.transition 2000, 4, :o2, 954658800
-
1
tz.transition 2000, 10, :o1, 972799200
-
1
tz.transition 2001, 4, :o2, 986108400
-
1
tz.transition 2001, 10, :o1, 1004248800
-
1
tz.transition 2002, 4, :o2, 1018162800
-
1
tz.transition 2002, 10, :o1, 1035698400
-
1
tz.transition 2003, 4, :o2, 1049612400
-
1
tz.transition 2003, 10, :o1, 1067148000
-
1
tz.transition 2004, 4, :o2, 1081062000
-
1
tz.transition 2004, 10, :o1, 1099202400
-
1
tz.transition 2005, 4, :o2, 1112511600
-
1
tz.transition 2005, 10, :o1, 1130652000
-
1
tz.transition 2006, 4, :o2, 1143961200
-
1
tz.transition 2006, 10, :o1, 1162101600
-
1
tz.transition 2007, 3, :o2, 1173596400
-
1
tz.transition 2007, 11, :o1, 1194156000
-
1
tz.transition 2008, 3, :o2, 1205046000
-
1
tz.transition 2008, 11, :o1, 1225605600
-
1
tz.transition 2009, 3, :o2, 1236495600
-
1
tz.transition 2009, 11, :o1, 1257055200
-
1
tz.transition 2010, 3, :o2, 1268550000
-
1
tz.transition 2010, 11, :o1, 1289109600
-
1
tz.transition 2011, 3, :o2, 1299999600
-
1
tz.transition 2011, 11, :o1, 1320559200
-
1
tz.transition 2012, 3, :o2, 1331449200
-
1
tz.transition 2012, 11, :o1, 1352008800
-
1
tz.transition 2013, 3, :o2, 1362898800
-
1
tz.transition 2013, 11, :o1, 1383458400
-
1
tz.transition 2014, 3, :o2, 1394348400
-
1
tz.transition 2014, 11, :o1, 1414908000
-
1
tz.transition 2015, 3, :o2, 1425798000
-
1
tz.transition 2015, 11, :o1, 1446357600
-
1
tz.transition 2016, 3, :o2, 1457852400
-
1
tz.transition 2016, 11, :o1, 1478412000
-
1
tz.transition 2017, 3, :o2, 1489302000
-
1
tz.transition 2017, 11, :o1, 1509861600
-
1
tz.transition 2018, 3, :o2, 1520751600
-
1
tz.transition 2018, 11, :o1, 1541311200
-
1
tz.transition 2019, 3, :o2, 1552201200
-
1
tz.transition 2019, 11, :o1, 1572760800
-
1
tz.transition 2020, 3, :o2, 1583650800
-
1
tz.transition 2020, 11, :o1, 1604210400
-
1
tz.transition 2021, 3, :o2, 1615705200
-
1
tz.transition 2021, 11, :o1, 1636264800
-
1
tz.transition 2022, 3, :o2, 1647154800
-
1
tz.transition 2022, 11, :o1, 1667714400
-
1
tz.transition 2023, 3, :o2, 1678604400
-
1
tz.transition 2023, 11, :o1, 1699164000
-
1
tz.transition 2024, 3, :o2, 1710054000
-
1
tz.transition 2024, 11, :o1, 1730613600
-
1
tz.transition 2025, 3, :o2, 1741503600
-
1
tz.transition 2025, 11, :o1, 1762063200
-
1
tz.transition 2026, 3, :o2, 1772953200
-
1
tz.transition 2026, 11, :o1, 1793512800
-
1
tz.transition 2027, 3, :o2, 1805007600
-
1
tz.transition 2027, 11, :o1, 1825567200
-
1
tz.transition 2028, 3, :o2, 1836457200
-
1
tz.transition 2028, 11, :o1, 1857016800
-
1
tz.transition 2029, 3, :o2, 1867906800
-
1
tz.transition 2029, 11, :o1, 1888466400
-
1
tz.transition 2030, 3, :o2, 1899356400
-
1
tz.transition 2030, 11, :o1, 1919916000
-
1
tz.transition 2031, 3, :o2, 1930806000
-
1
tz.transition 2031, 11, :o1, 1951365600
-
1
tz.transition 2032, 3, :o2, 1962860400
-
1
tz.transition 2032, 11, :o1, 1983420000
-
1
tz.transition 2033, 3, :o2, 1994310000
-
1
tz.transition 2033, 11, :o1, 2014869600
-
1
tz.transition 2034, 3, :o2, 2025759600
-
1
tz.transition 2034, 11, :o1, 2046319200
-
1
tz.transition 2035, 3, :o2, 2057209200
-
1
tz.transition 2035, 11, :o1, 2077768800
-
1
tz.transition 2036, 3, :o2, 2088658800
-
1
tz.transition 2036, 11, :o1, 2109218400
-
1
tz.transition 2037, 3, :o2, 2120108400
-
1
tz.transition 2037, 11, :o1, 2140668000
-
1
tz.transition 2038, 3, :o2, 59171923, 24
-
1
tz.transition 2038, 11, :o1, 9862939, 4
-
1
tz.transition 2039, 3, :o2, 59180659, 24
-
1
tz.transition 2039, 11, :o1, 9864395, 4
-
1
tz.transition 2040, 3, :o2, 59189395, 24
-
1
tz.transition 2040, 11, :o1, 9865851, 4
-
1
tz.transition 2041, 3, :o2, 59198131, 24
-
1
tz.transition 2041, 11, :o1, 9867307, 4
-
1
tz.transition 2042, 3, :o2, 59206867, 24
-
1
tz.transition 2042, 11, :o1, 9868763, 4
-
1
tz.transition 2043, 3, :o2, 59215603, 24
-
1
tz.transition 2043, 11, :o1, 9870219, 4
-
1
tz.transition 2044, 3, :o2, 59224507, 24
-
1
tz.transition 2044, 11, :o1, 9871703, 4
-
1
tz.transition 2045, 3, :o2, 59233243, 24
-
1
tz.transition 2045, 11, :o1, 9873159, 4
-
1
tz.transition 2046, 3, :o2, 59241979, 24
-
1
tz.transition 2046, 11, :o1, 9874615, 4
-
1
tz.transition 2047, 3, :o2, 59250715, 24
-
1
tz.transition 2047, 11, :o1, 9876071, 4
-
1
tz.transition 2048, 3, :o2, 59259451, 24
-
1
tz.transition 2048, 11, :o1, 9877527, 4
-
1
tz.transition 2049, 3, :o2, 59268355, 24
-
1
tz.transition 2049, 11, :o1, 9879011, 4
-
1
tz.transition 2050, 3, :o2, 59277091, 24
-
1
tz.transition 2050, 11, :o1, 9880467, 4
-
end
-
end
-
end
-
end
-
end
-
1
module TZInfo
-
1
module Definitions
-
1
module America
-
1
module Phoenix
-
1
include TimezoneDefinition
-
-
1
timezone 'America/Phoenix' do |tz|
-
1
tz.offset :o0, -26898, 0, :LMT
-
1
tz.offset :o1, -25200, 0, :MST
-
1
tz.offset :o2, -25200, 3600, :MDT
-
1
tz.offset :o3, -25200, 3600, :MWT
-
-
1
tz.transition 1883, 11, :o1, 57819199, 24
-
1
tz.transition 1918, 3, :o2, 19373471, 8
-
1
tz.transition 1918, 10, :o1, 14531363, 6
-
1
tz.transition 1919, 3, :o2, 19376383, 8
-
1
tz.transition 1919, 10, :o1, 14533547, 6
-
1
tz.transition 1942, 2, :o3, 19443199, 8
-
1
tz.transition 1944, 1, :o1, 3500770681, 1440
-
1
tz.transition 1944, 4, :o3, 3500901781, 1440
-
1
tz.transition 1944, 10, :o1, 3501165241, 1440
-
1
tz.transition 1967, 4, :o2, 19516887, 8
-
1
tz.transition 1967, 10, :o1, 14638757, 6
-
end
-
end
-
end
-
end
-
end
-
1
module TZInfo
-
1
module Definitions
-
1
module America
-
1
module Regina
-
1
include TimezoneDefinition
-
-
1
timezone 'America/Regina' do |tz|
-
1
tz.offset :o0, -25116, 0, :LMT
-
1
tz.offset :o1, -25200, 0, :MST
-
1
tz.offset :o2, -25200, 3600, :MDT
-
1
tz.offset :o3, -25200, 3600, :MWT
-
1
tz.offset :o4, -25200, 3600, :MPT
-
1
tz.offset :o5, -21600, 0, :CST
-
-
1
tz.transition 1905, 9, :o1, 17403046493, 7200
-
1
tz.transition 1918, 4, :o2, 19373583, 8
-
1
tz.transition 1918, 10, :o1, 14531363, 6
-
1
tz.transition 1930, 5, :o2, 58226419, 24
-
1
tz.transition 1930, 10, :o1, 9705019, 4
-
1
tz.transition 1931, 5, :o2, 58235155, 24
-
1
tz.transition 1931, 10, :o1, 9706475, 4
-
1
tz.transition 1932, 5, :o2, 58243891, 24
-
1
tz.transition 1932, 10, :o1, 9707931, 4
-
1
tz.transition 1933, 5, :o2, 58252795, 24
-
1
tz.transition 1933, 10, :o1, 9709387, 4
-
1
tz.transition 1934, 5, :o2, 58261531, 24
-
1
tz.transition 1934, 10, :o1, 9710871, 4
-
1
tz.transition 1937, 4, :o2, 58287235, 24
-
1
tz.transition 1937, 10, :o1, 9715267, 4
-
1
tz.transition 1938, 4, :o2, 58295971, 24
-
1
tz.transition 1938, 10, :o1, 9716695, 4
-
1
tz.transition 1939, 4, :o2, 58304707, 24
-
1
tz.transition 1939, 10, :o1, 9718179, 4
-
1
tz.transition 1940, 4, :o2, 58313611, 24
-
1
tz.transition 1940, 10, :o1, 9719663, 4
-
1
tz.transition 1941, 4, :o2, 58322347, 24
-
1
tz.transition 1941, 10, :o1, 9721119, 4
-
1
tz.transition 1942, 2, :o3, 19443199, 8
-
1
tz.transition 1945, 8, :o4, 58360379, 24
-
1
tz.transition 1945, 9, :o1, 14590373, 6
-
1
tz.transition 1946, 4, :o2, 19455399, 8
-
1
tz.transition 1946, 10, :o1, 14592641, 6
-
1
tz.transition 1947, 4, :o2, 19458423, 8
-
1
tz.transition 1947, 9, :o1, 14594741, 6
-
1
tz.transition 1948, 4, :o2, 19461335, 8
-
1
tz.transition 1948, 9, :o1, 14596925, 6
-
1
tz.transition 1949, 4, :o2, 19464247, 8
-
1
tz.transition 1949, 9, :o1, 14599109, 6
-
1
tz.transition 1950, 4, :o2, 19467215, 8
-
1
tz.transition 1950, 9, :o1, 14601293, 6
-
1
tz.transition 1951, 4, :o2, 19470127, 8
-
1
tz.transition 1951, 9, :o1, 14603519, 6
-
1
tz.transition 1952, 4, :o2, 19473039, 8
-
1
tz.transition 1952, 9, :o1, 14605703, 6
-
1
tz.transition 1953, 4, :o2, 19475951, 8
-
1
tz.transition 1953, 9, :o1, 14607887, 6
-
1
tz.transition 1954, 4, :o2, 19478863, 8
-
1
tz.transition 1954, 9, :o1, 14610071, 6
-
1
tz.transition 1955, 4, :o2, 19481775, 8
-
1
tz.transition 1955, 9, :o1, 14612255, 6
-
1
tz.transition 1956, 4, :o2, 19484743, 8
-
1
tz.transition 1956, 9, :o1, 14614481, 6
-
1
tz.transition 1957, 4, :o2, 19487655, 8
-
1
tz.transition 1957, 9, :o1, 14616665, 6
-
1
tz.transition 1959, 4, :o2, 19493479, 8
-
1
tz.transition 1959, 10, :o1, 14621201, 6
-
1
tz.transition 1960, 4, :o5, 19496391, 8
-
end
-
end
-
end
-
end
-
end
-
1
module TZInfo
-
1
module Definitions
-
1
module America
-
1
module Santiago
-
1
include TimezoneDefinition
-
-
1
timezone 'America/Santiago' do |tz|
-
1
tz.offset :o0, -16966, 0, :LMT
-
1
tz.offset :o1, -16966, 0, :SMT
-
1
tz.offset :o2, -18000, 0, :CLT
-
1
tz.offset :o3, -14400, 0, :CLT
-
1
tz.offset :o4, -18000, 3600, :CLST
-
1
tz.offset :o5, -14400, 3600, :CLST
-
-
1
tz.transition 1890, 1, :o1, 104171127683, 43200
-
1
tz.transition 1910, 1, :o2, 104486660483, 43200
-
1
tz.transition 1916, 7, :o1, 58105097, 24
-
1
tz.transition 1918, 9, :o3, 104623388483, 43200
-
1
tz.transition 1919, 7, :o1, 7266422, 3
-
1
tz.transition 1927, 9, :o4, 104765386883, 43200
-
1
tz.transition 1928, 4, :o2, 7276013, 3
-
1
tz.transition 1928, 9, :o4, 58211777, 24
-
1
tz.transition 1929, 4, :o2, 7277108, 3
-
1
tz.transition 1929, 9, :o4, 58220537, 24
-
1
tz.transition 1930, 4, :o2, 7278203, 3
-
1
tz.transition 1930, 9, :o4, 58229297, 24
-
1
tz.transition 1931, 4, :o2, 7279298, 3
-
1
tz.transition 1931, 9, :o4, 58238057, 24
-
1
tz.transition 1932, 4, :o2, 7280396, 3
-
1
tz.transition 1932, 9, :o4, 58246841, 24
-
1
tz.transition 1942, 6, :o2, 7291535, 3
-
1
tz.transition 1942, 8, :o4, 58333745, 24
-
1
tz.transition 1946, 9, :o2, 19456517, 8
-
1
tz.transition 1947, 5, :o3, 58375865, 24
-
1
tz.transition 1968, 11, :o5, 7320491, 3
-
1
tz.transition 1969, 3, :o3, 19522485, 8
-
1
tz.transition 1969, 11, :o5, 7321646, 3
-
1
tz.transition 1970, 3, :o3, 7527600
-
1
tz.transition 1970, 10, :o5, 24465600
-
1
tz.transition 1971, 3, :o3, 37767600
-
1
tz.transition 1971, 10, :o5, 55915200
-
1
tz.transition 1972, 3, :o3, 69217200
-
1
tz.transition 1972, 10, :o5, 87969600
-
1
tz.transition 1973, 3, :o3, 100666800
-
1
tz.transition 1973, 9, :o5, 118209600
-
1
tz.transition 1974, 3, :o3, 132116400
-
1
tz.transition 1974, 10, :o5, 150868800
-
1
tz.transition 1975, 3, :o3, 163566000
-
1
tz.transition 1975, 10, :o5, 182318400
-
1
tz.transition 1976, 3, :o3, 195620400
-
1
tz.transition 1976, 10, :o5, 213768000
-
1
tz.transition 1977, 3, :o3, 227070000
-
1
tz.transition 1977, 10, :o5, 245217600
-
1
tz.transition 1978, 3, :o3, 258519600
-
1
tz.transition 1978, 10, :o5, 277272000
-
1
tz.transition 1979, 3, :o3, 289969200
-
1
tz.transition 1979, 10, :o5, 308721600
-
1
tz.transition 1980, 3, :o3, 321418800
-
1
tz.transition 1980, 10, :o5, 340171200
-
1
tz.transition 1981, 3, :o3, 353473200
-
1
tz.transition 1981, 10, :o5, 371620800
-
1
tz.transition 1982, 3, :o3, 384922800
-
1
tz.transition 1982, 10, :o5, 403070400
-
1
tz.transition 1983, 3, :o3, 416372400
-
1
tz.transition 1983, 10, :o5, 434520000
-
1
tz.transition 1984, 3, :o3, 447822000
-
1
tz.transition 1984, 10, :o5, 466574400
-
1
tz.transition 1985, 3, :o3, 479271600
-
1
tz.transition 1985, 10, :o5, 498024000
-
1
tz.transition 1986, 3, :o3, 510721200
-
1
tz.transition 1986, 10, :o5, 529473600
-
1
tz.transition 1987, 4, :o3, 545194800
-
1
tz.transition 1987, 10, :o5, 560923200
-
1
tz.transition 1988, 3, :o3, 574225200
-
1
tz.transition 1988, 10, :o5, 591768000
-
1
tz.transition 1989, 3, :o3, 605674800
-
1
tz.transition 1989, 10, :o5, 624427200
-
1
tz.transition 1990, 3, :o3, 637729200
-
1
tz.transition 1990, 9, :o5, 653457600
-
1
tz.transition 1991, 3, :o3, 668574000
-
1
tz.transition 1991, 10, :o5, 687326400
-
1
tz.transition 1992, 3, :o3, 700628400
-
1
tz.transition 1992, 10, :o5, 718776000
-
1
tz.transition 1993, 3, :o3, 732078000
-
1
tz.transition 1993, 10, :o5, 750225600
-
1
tz.transition 1994, 3, :o3, 763527600
-
1
tz.transition 1994, 10, :o5, 781675200
-
1
tz.transition 1995, 3, :o3, 794977200
-
1
tz.transition 1995, 10, :o5, 813729600
-
1
tz.transition 1996, 3, :o3, 826426800
-
1
tz.transition 1996, 10, :o5, 845179200
-
1
tz.transition 1997, 3, :o3, 859690800
-
1
tz.transition 1997, 10, :o5, 876628800
-
1
tz.transition 1998, 3, :o3, 889930800
-
1
tz.transition 1998, 9, :o5, 906868800
-
1
tz.transition 1999, 4, :o3, 923194800
-
1
tz.transition 1999, 10, :o5, 939528000
-
1
tz.transition 2000, 3, :o3, 952830000
-
1
tz.transition 2000, 10, :o5, 971582400
-
1
tz.transition 2001, 3, :o3, 984279600
-
1
tz.transition 2001, 10, :o5, 1003032000
-
1
tz.transition 2002, 3, :o3, 1015729200
-
1
tz.transition 2002, 10, :o5, 1034481600
-
1
tz.transition 2003, 3, :o3, 1047178800
-
1
tz.transition 2003, 10, :o5, 1065931200
-
1
tz.transition 2004, 3, :o3, 1079233200
-
1
tz.transition 2004, 10, :o5, 1097380800
-
1
tz.transition 2005, 3, :o3, 1110682800
-
1
tz.transition 2005, 10, :o5, 1128830400
-
1
tz.transition 2006, 3, :o3, 1142132400
-
1
tz.transition 2006, 10, :o5, 1160884800
-
1
tz.transition 2007, 3, :o3, 1173582000
-
1
tz.transition 2007, 10, :o5, 1192334400
-
1
tz.transition 2008, 3, :o3, 1206846000
-
1
tz.transition 2008, 10, :o5, 1223784000
-
1
tz.transition 2009, 3, :o3, 1237086000
-
1
tz.transition 2009, 10, :o5, 1255233600
-
1
tz.transition 2010, 4, :o3, 1270350000
-
1
tz.transition 2010, 10, :o5, 1286683200
-
1
tz.transition 2011, 5, :o3, 1304823600
-
1
tz.transition 2011, 8, :o5, 1313899200
-
1
tz.transition 2012, 4, :o3, 1335668400
-
1
tz.transition 2012, 9, :o5, 1346558400
-
1
tz.transition 2013, 3, :o3, 1362884400
-
1
tz.transition 2013, 10, :o5, 1381636800
-
1
tz.transition 2014, 3, :o3, 1394334000
-
1
tz.transition 2014, 10, :o5, 1413086400
-
1
tz.transition 2015, 3, :o3, 1426388400
-
1
tz.transition 2015, 10, :o5, 1444536000
-
1
tz.transition 2016, 3, :o3, 1457838000
-
1
tz.transition 2016, 10, :o5, 1475985600
-
1
tz.transition 2017, 3, :o3, 1489287600
-
1
tz.transition 2017, 10, :o5, 1508040000
-
1
tz.transition 2018, 3, :o3, 1520737200
-
1
tz.transition 2018, 10, :o5, 1539489600
-
1
tz.transition 2019, 3, :o3, 1552186800
-
1
tz.transition 2019, 10, :o5, 1570939200
-
1
tz.transition 2020, 3, :o3, 1584241200
-
1
tz.transition 2020, 10, :o5, 1602388800
-
1
tz.transition 2021, 3, :o3, 1615690800
-
1
tz.transition 2021, 10, :o5, 1633838400
-
1
tz.transition 2022, 3, :o3, 1647140400
-
1
tz.transition 2022, 10, :o5, 1665288000
-
1
tz.transition 2023, 3, :o3, 1678590000
-
1
tz.transition 2023, 10, :o5, 1697342400
-
1
tz.transition 2024, 3, :o3, 1710039600
-
1
tz.transition 2024, 10, :o5, 1728792000
-
1
tz.transition 2025, 3, :o3, 1741489200
-
1
tz.transition 2025, 10, :o5, 1760241600
-
1
tz.transition 2026, 3, :o3, 1773543600
-
1
tz.transition 2026, 10, :o5, 1791691200
-
1
tz.transition 2027, 3, :o3, 1804993200
-
1
tz.transition 2027, 10, :o5, 1823140800
-
1
tz.transition 2028, 3, :o3, 1836442800
-
1
tz.transition 2028, 10, :o5, 1855195200
-
1
tz.transition 2029, 3, :o3, 1867892400
-
1
tz.transition 2029, 10, :o5, 1886644800
-
1
tz.transition 2030, 3, :o3, 1899342000
-
1
tz.transition 2030, 10, :o5, 1918094400
-
1
tz.transition 2031, 3, :o3, 1930791600
-
1
tz.transition 2031, 10, :o5, 1949544000
-
1
tz.transition 2032, 3, :o3, 1962846000
-
1
tz.transition 2032, 10, :o5, 1980993600
-
1
tz.transition 2033, 3, :o3, 1994295600
-
1
tz.transition 2033, 10, :o5, 2012443200
-
1
tz.transition 2034, 3, :o3, 2025745200
-
1
tz.transition 2034, 10, :o5, 2044497600
-
1
tz.transition 2035, 3, :o3, 2057194800
-
1
tz.transition 2035, 10, :o5, 2075947200
-
1
tz.transition 2036, 3, :o3, 2088644400
-
1
tz.transition 2036, 10, :o5, 2107396800
-
1
tz.transition 2037, 3, :o3, 2120698800
-
1
tz.transition 2037, 10, :o5, 2138846400
-
1
tz.transition 2038, 3, :o3, 19723973, 8
-
1
tz.transition 2038, 10, :o5, 7397120, 3
-
1
tz.transition 2039, 3, :o3, 19726885, 8
-
1
tz.transition 2039, 10, :o5, 7398212, 3
-
1
tz.transition 2040, 3, :o3, 19729797, 8
-
1
tz.transition 2040, 10, :o5, 7399325, 3
-
1
tz.transition 2041, 3, :o3, 19732709, 8
-
1
tz.transition 2041, 10, :o5, 7400417, 3
-
1
tz.transition 2042, 3, :o3, 19735621, 8
-
1
tz.transition 2042, 10, :o5, 7401509, 3
-
1
tz.transition 2043, 3, :o3, 19738589, 8
-
1
tz.transition 2043, 10, :o5, 7402601, 3
-
1
tz.transition 2044, 3, :o3, 19741501, 8
-
1
tz.transition 2044, 10, :o5, 7403693, 3
-
1
tz.transition 2045, 3, :o3, 19744413, 8
-
1
tz.transition 2045, 10, :o5, 7404806, 3
-
1
tz.transition 2046, 3, :o3, 19747325, 8
-
1
tz.transition 2046, 10, :o5, 7405898, 3
-
1
tz.transition 2047, 3, :o3, 19750237, 8
-
1
tz.transition 2047, 10, :o5, 7406990, 3
-
1
tz.transition 2048, 3, :o3, 19753205, 8
-
1
tz.transition 2048, 10, :o5, 7408082, 3
-
1
tz.transition 2049, 3, :o3, 19756117, 8
-
1
tz.transition 2049, 10, :o5, 7409174, 3
-
1
tz.transition 2050, 3, :o3, 19759029, 8
-
end
-
end
-
end
-
end
-
end
-
1
module TZInfo
-
1
module Definitions
-
1
module America
-
1
module Sao_Paulo
-
1
include TimezoneDefinition
-
-
1
timezone 'America/Sao_Paulo' do |tz|
-
1
tz.offset :o0, -11188, 0, :LMT
-
1
tz.offset :o1, -10800, 0, :BRT
-
1
tz.offset :o2, -10800, 3600, :BRST
-
-
1
tz.transition 1914, 1, :o1, 52274886397, 21600
-
1
tz.transition 1931, 10, :o2, 29119417, 12
-
1
tz.transition 1932, 4, :o1, 29121583, 12
-
1
tz.transition 1932, 10, :o2, 19415869, 8
-
1
tz.transition 1933, 4, :o1, 29125963, 12
-
1
tz.transition 1949, 12, :o2, 19466013, 8
-
1
tz.transition 1950, 4, :o1, 19467101, 8
-
1
tz.transition 1950, 12, :o2, 19468933, 8
-
1
tz.transition 1951, 4, :o1, 29204851, 12
-
1
tz.transition 1951, 12, :o2, 19471853, 8
-
1
tz.transition 1952, 4, :o1, 29209243, 12
-
1
tz.transition 1952, 12, :o2, 19474781, 8
-
1
tz.transition 1953, 3, :o1, 29213251, 12
-
1
tz.transition 1963, 10, :o2, 19506605, 8
-
1
tz.transition 1964, 3, :o1, 29261467, 12
-
1
tz.transition 1965, 1, :o2, 19510333, 8
-
1
tz.transition 1965, 3, :o1, 29266207, 12
-
1
tz.transition 1965, 12, :o2, 19512765, 8
-
1
tz.transition 1966, 3, :o1, 29270227, 12
-
1
tz.transition 1966, 11, :o2, 19515445, 8
-
1
tz.transition 1967, 3, :o1, 29274607, 12
-
1
tz.transition 1967, 11, :o2, 19518365, 8
-
1
tz.transition 1968, 3, :o1, 29278999, 12
-
1
tz.transition 1985, 11, :o2, 499748400
-
1
tz.transition 1986, 3, :o1, 511236000
-
1
tz.transition 1986, 10, :o2, 530593200
-
1
tz.transition 1987, 2, :o1, 540266400
-
1
tz.transition 1987, 10, :o2, 562129200
-
1
tz.transition 1988, 2, :o1, 571197600
-
1
tz.transition 1988, 10, :o2, 592974000
-
1
tz.transition 1989, 1, :o1, 602042400
-
1
tz.transition 1989, 10, :o2, 624423600
-
1
tz.transition 1990, 2, :o1, 634701600
-
1
tz.transition 1990, 10, :o2, 656478000
-
1
tz.transition 1991, 2, :o1, 666756000
-
1
tz.transition 1991, 10, :o2, 687927600
-
1
tz.transition 1992, 2, :o1, 697600800
-
1
tz.transition 1992, 10, :o2, 719982000
-
1
tz.transition 1993, 1, :o1, 728445600
-
1
tz.transition 1993, 10, :o2, 750826800
-
1
tz.transition 1994, 2, :o1, 761709600
-
1
tz.transition 1994, 10, :o2, 782276400
-
1
tz.transition 1995, 2, :o1, 793159200
-
1
tz.transition 1995, 10, :o2, 813726000
-
1
tz.transition 1996, 2, :o1, 824004000
-
1
tz.transition 1996, 10, :o2, 844570800
-
1
tz.transition 1997, 2, :o1, 856058400
-
1
tz.transition 1997, 10, :o2, 876106800
-
1
tz.transition 1998, 3, :o1, 888717600
-
1
tz.transition 1998, 10, :o2, 908074800
-
1
tz.transition 1999, 2, :o1, 919562400
-
1
tz.transition 1999, 10, :o2, 938919600
-
1
tz.transition 2000, 2, :o1, 951616800
-
1
tz.transition 2000, 10, :o2, 970974000
-
1
tz.transition 2001, 2, :o1, 982461600
-
1
tz.transition 2001, 10, :o2, 1003028400
-
1
tz.transition 2002, 2, :o1, 1013911200
-
1
tz.transition 2002, 11, :o2, 1036292400
-
1
tz.transition 2003, 2, :o1, 1045360800
-
1
tz.transition 2003, 10, :o2, 1066532400
-
1
tz.transition 2004, 2, :o1, 1076810400
-
1
tz.transition 2004, 11, :o2, 1099364400
-
1
tz.transition 2005, 2, :o1, 1108864800
-
1
tz.transition 2005, 10, :o2, 1129431600
-
1
tz.transition 2006, 2, :o1, 1140314400
-
1
tz.transition 2006, 11, :o2, 1162695600
-
1
tz.transition 2007, 2, :o1, 1172368800
-
1
tz.transition 2007, 10, :o2, 1192330800
-
1
tz.transition 2008, 2, :o1, 1203213600
-
1
tz.transition 2008, 10, :o2, 1224385200
-
1
tz.transition 2009, 2, :o1, 1234663200
-
1
tz.transition 2009, 10, :o2, 1255834800
-
1
tz.transition 2010, 2, :o1, 1266717600
-
1
tz.transition 2010, 10, :o2, 1287284400
-
1
tz.transition 2011, 2, :o1, 1298167200
-
1
tz.transition 2011, 10, :o2, 1318734000
-
1
tz.transition 2012, 2, :o1, 1330221600
-
1
tz.transition 2012, 10, :o2, 1350788400
-
1
tz.transition 2013, 2, :o1, 1361066400
-
1
tz.transition 2013, 10, :o2, 1382238000
-
1
tz.transition 2014, 2, :o1, 1392516000
-
1
tz.transition 2014, 10, :o2, 1413687600
-
1
tz.transition 2015, 2, :o1, 1424570400
-
1
tz.transition 2015, 10, :o2, 1445137200
-
1
tz.transition 2016, 2, :o1, 1456020000
-
1
tz.transition 2016, 10, :o2, 1476586800
-
1
tz.transition 2017, 2, :o1, 1487469600
-
1
tz.transition 2017, 10, :o2, 1508036400
-
1
tz.transition 2018, 2, :o1, 1518919200
-
1
tz.transition 2018, 10, :o2, 1540090800
-
1
tz.transition 2019, 2, :o1, 1550368800
-
1
tz.transition 2019, 10, :o2, 1571540400
-
1
tz.transition 2020, 2, :o1, 1581818400
-
1
tz.transition 2020, 10, :o2, 1602990000
-
1
tz.transition 2021, 2, :o1, 1613872800
-
1
tz.transition 2021, 10, :o2, 1634439600
-
1
tz.transition 2022, 2, :o1, 1645322400
-
1
tz.transition 2022, 10, :o2, 1665889200
-
1
tz.transition 2023, 2, :o1, 1677376800
-
1
tz.transition 2023, 10, :o2, 1697338800
-
1
tz.transition 2024, 2, :o1, 1708221600
-
1
tz.transition 2024, 10, :o2, 1729393200
-
1
tz.transition 2025, 2, :o1, 1739671200
-
1
tz.transition 2025, 10, :o2, 1760842800
-
1
tz.transition 2026, 2, :o1, 1771725600
-
1
tz.transition 2026, 10, :o2, 1792292400
-
1
tz.transition 2027, 2, :o1, 1803175200
-
1
tz.transition 2027, 10, :o2, 1823742000
-
1
tz.transition 2028, 2, :o1, 1834624800
-
1
tz.transition 2028, 10, :o2, 1855191600
-
1
tz.transition 2029, 2, :o1, 1866074400
-
1
tz.transition 2029, 10, :o2, 1887246000
-
1
tz.transition 2030, 2, :o1, 1897524000
-
1
tz.transition 2030, 10, :o2, 1918695600
-
1
tz.transition 2031, 2, :o1, 1928973600
-
1
tz.transition 2031, 10, :o2, 1950145200
-
1
tz.transition 2032, 2, :o1, 1960423200
-
1
tz.transition 2032, 10, :o2, 1981594800
-
1
tz.transition 2033, 2, :o1, 1992477600
-
1
tz.transition 2033, 10, :o2, 2013044400
-
1
tz.transition 2034, 2, :o1, 2024532000
-
1
tz.transition 2034, 10, :o2, 2044494000
-
1
tz.transition 2035, 2, :o1, 2055376800
-
1
tz.transition 2035, 10, :o2, 2076548400
-
1
tz.transition 2036, 2, :o1, 2086826400
-
1
tz.transition 2036, 10, :o2, 2107998000
-
1
tz.transition 2037, 2, :o1, 2118880800
-
1
tz.transition 2037, 10, :o2, 2139447600
-
1
tz.transition 2038, 2, :o1, 29585707, 12
-
1
tz.transition 2038, 10, :o2, 19725709, 8
-
1
tz.transition 2039, 2, :o1, 29590075, 12
-
1
tz.transition 2039, 10, :o2, 19728621, 8
-
1
tz.transition 2040, 2, :o1, 29594443, 12
-
1
tz.transition 2040, 10, :o2, 19731589, 8
-
1
tz.transition 2041, 2, :o1, 29598811, 12
-
1
tz.transition 2041, 10, :o2, 19734501, 8
-
1
tz.transition 2042, 2, :o1, 29603179, 12
-
1
tz.transition 2042, 10, :o2, 19737413, 8
-
1
tz.transition 2043, 2, :o1, 29607547, 12
-
1
tz.transition 2043, 10, :o2, 19740325, 8
-
1
tz.transition 2044, 2, :o1, 29611999, 12
-
1
tz.transition 2044, 10, :o2, 19743237, 8
-
1
tz.transition 2045, 2, :o1, 29616367, 12
-
1
tz.transition 2045, 10, :o2, 19746149, 8
-
1
tz.transition 2046, 2, :o1, 29620735, 12
-
1
tz.transition 2046, 10, :o2, 19749117, 8
-
1
tz.transition 2047, 2, :o1, 29625103, 12
-
1
tz.transition 2047, 10, :o2, 19752029, 8
-
1
tz.transition 2048, 2, :o1, 29629471, 12
-
1
tz.transition 2048, 10, :o2, 19754941, 8
-
1
tz.transition 2049, 2, :o1, 29633923, 12
-
1
tz.transition 2049, 10, :o2, 19757853, 8
-
1
tz.transition 2050, 2, :o1, 29638291, 12
-
end
-
end
-
end
-
end
-
end
-
1
module TZInfo
-
1
module Definitions
-
1
module America
-
1
module St_Johns
-
1
include TimezoneDefinition
-
-
1
timezone 'America/St_Johns' do |tz|
-
1
tz.offset :o0, -12652, 0, :LMT
-
1
tz.offset :o1, -12652, 0, :NST
-
1
tz.offset :o2, -12652, 3600, :NDT
-
1
tz.offset :o3, -12600, 0, :NST
-
1
tz.offset :o4, -12600, 3600, :NDT
-
1
tz.offset :o5, -12600, 3600, :NWT
-
1
tz.offset :o6, -12600, 3600, :NPT
-
1
tz.offset :o7, -12600, 7200, :NDDT
-
-
1
tz.transition 1884, 1, :o1, 52038215563, 21600
-
1
tz.transition 1917, 4, :o2, 52300657363, 21600
-
1
tz.transition 1917, 9, :o1, 52304155663, 21600
-
1
tz.transition 1918, 4, :o2, 52308670963, 21600
-
1
tz.transition 1918, 10, :o1, 52312903663, 21600
-
1
tz.transition 1919, 5, :o2, 52317027463, 21600
-
1
tz.transition 1919, 8, :o1, 52319164963, 21600
-
1
tz.transition 1920, 5, :o2, 52324868263, 21600
-
1
tz.transition 1920, 11, :o1, 52328798563, 21600
-
1
tz.transition 1921, 5, :o2, 52332730663, 21600
-
1
tz.transition 1921, 10, :o1, 52336660963, 21600
-
1
tz.transition 1922, 5, :o2, 52340744263, 21600
-
1
tz.transition 1922, 10, :o1, 52344523363, 21600
-
1
tz.transition 1923, 5, :o2, 52348606663, 21600
-
1
tz.transition 1923, 10, :o1, 52352385763, 21600
-
1
tz.transition 1924, 5, :o2, 52356469063, 21600
-
1
tz.transition 1924, 10, :o1, 52360248163, 21600
-
1
tz.transition 1925, 5, :o2, 52364331463, 21600
-
1
tz.transition 1925, 10, :o1, 52368110563, 21600
-
1
tz.transition 1926, 5, :o2, 52372193863, 21600
-
1
tz.transition 1926, 11, :o1, 52376124163, 21600
-
1
tz.transition 1927, 5, :o2, 52380056263, 21600
-
1
tz.transition 1927, 10, :o1, 52383986563, 21600
-
1
tz.transition 1928, 5, :o2, 52388069863, 21600
-
1
tz.transition 1928, 10, :o1, 52391848963, 21600
-
1
tz.transition 1929, 5, :o2, 52395932263, 21600
-
1
tz.transition 1929, 10, :o1, 52399711363, 21600
-
1
tz.transition 1930, 5, :o2, 52403794663, 21600
-
1
tz.transition 1930, 10, :o1, 52407573763, 21600
-
1
tz.transition 1931, 5, :o2, 52411657063, 21600
-
1
tz.transition 1931, 10, :o1, 52415436163, 21600
-
1
tz.transition 1932, 5, :o2, 52419519463, 21600
-
1
tz.transition 1932, 10, :o1, 52423449763, 21600
-
1
tz.transition 1933, 5, :o2, 52427533063, 21600
-
1
tz.transition 1933, 10, :o1, 52431312163, 21600
-
1
tz.transition 1934, 5, :o2, 52435395463, 21600
-
1
tz.transition 1934, 10, :o1, 52439174563, 21600
-
1
tz.transition 1935, 3, :o3, 52442459563, 21600
-
1
tz.transition 1935, 5, :o4, 116540573, 48
-
1
tz.transition 1935, 10, :o3, 38849657, 16
-
1
tz.transition 1936, 5, :o4, 116558383, 48
-
1
tz.transition 1936, 10, :o3, 116565437, 48
-
1
tz.transition 1937, 5, :o4, 116575855, 48
-
1
tz.transition 1937, 10, :o3, 116582909, 48
-
1
tz.transition 1938, 5, :o4, 116593327, 48
-
1
tz.transition 1938, 10, :o3, 116600381, 48
-
1
tz.transition 1939, 5, :o4, 116611135, 48
-
1
tz.transition 1939, 10, :o3, 116617853, 48
-
1
tz.transition 1940, 5, :o4, 116628607, 48
-
1
tz.transition 1940, 10, :o3, 116635661, 48
-
1
tz.transition 1941, 5, :o4, 116646079, 48
-
1
tz.transition 1941, 10, :o3, 116653133, 48
-
1
tz.transition 1942, 5, :o5, 116663551, 48
-
1
tz.transition 1945, 8, :o6, 58360379, 24
-
1
tz.transition 1945, 9, :o3, 38907659, 16
-
1
tz.transition 1946, 5, :o4, 116733731, 48
-
1
tz.transition 1946, 10, :o3, 38913595, 16
-
1
tz.transition 1947, 5, :o4, 116751203, 48
-
1
tz.transition 1947, 10, :o3, 38919419, 16
-
1
tz.transition 1948, 5, :o4, 116768675, 48
-
1
tz.transition 1948, 10, :o3, 38925243, 16
-
1
tz.transition 1949, 5, :o4, 116786147, 48
-
1
tz.transition 1949, 10, :o3, 38931067, 16
-
1
tz.transition 1950, 5, :o4, 116803955, 48
-
1
tz.transition 1950, 10, :o3, 38937003, 16
-
1
tz.transition 1951, 4, :o4, 116820755, 48
-
1
tz.transition 1951, 9, :o3, 38942715, 16
-
1
tz.transition 1952, 4, :o4, 116838227, 48
-
1
tz.transition 1952, 9, :o3, 38948539, 16
-
1
tz.transition 1953, 4, :o4, 116855699, 48
-
1
tz.transition 1953, 9, :o3, 38954363, 16
-
1
tz.transition 1954, 4, :o4, 116873171, 48
-
1
tz.transition 1954, 9, :o3, 38960187, 16
-
1
tz.transition 1955, 4, :o4, 116890643, 48
-
1
tz.transition 1955, 9, :o3, 38966011, 16
-
1
tz.transition 1956, 4, :o4, 116908451, 48
-
1
tz.transition 1956, 9, :o3, 38971947, 16
-
1
tz.transition 1957, 4, :o4, 116925923, 48
-
1
tz.transition 1957, 9, :o3, 38977771, 16
-
1
tz.transition 1958, 4, :o4, 116943395, 48
-
1
tz.transition 1958, 9, :o3, 38983595, 16
-
1
tz.transition 1959, 4, :o4, 116960867, 48
-
1
tz.transition 1959, 9, :o3, 38989419, 16
-
1
tz.transition 1960, 4, :o4, 116978339, 48
-
1
tz.transition 1960, 10, :o3, 38995803, 16
-
1
tz.transition 1961, 4, :o4, 116996147, 48
-
1
tz.transition 1961, 10, :o3, 39001627, 16
-
1
tz.transition 1962, 4, :o4, 117013619, 48
-
1
tz.transition 1962, 10, :o3, 39007451, 16
-
1
tz.transition 1963, 4, :o4, 117031091, 48
-
1
tz.transition 1963, 10, :o3, 39013275, 16
-
1
tz.transition 1964, 4, :o4, 117048563, 48
-
1
tz.transition 1964, 10, :o3, 39019099, 16
-
1
tz.transition 1965, 4, :o4, 117066035, 48
-
1
tz.transition 1965, 10, :o3, 39025035, 16
-
1
tz.transition 1966, 4, :o4, 117083507, 48
-
1
tz.transition 1966, 10, :o3, 39030859, 16
-
1
tz.transition 1967, 4, :o4, 117101315, 48
-
1
tz.transition 1967, 10, :o3, 39036683, 16
-
1
tz.transition 1968, 4, :o4, 117118787, 48
-
1
tz.transition 1968, 10, :o3, 39042507, 16
-
1
tz.transition 1969, 4, :o4, 117136259, 48
-
1
tz.transition 1969, 10, :o3, 39048331, 16
-
1
tz.transition 1970, 4, :o4, 9955800
-
1
tz.transition 1970, 10, :o3, 25677000
-
1
tz.transition 1971, 4, :o4, 41405400
-
1
tz.transition 1971, 10, :o3, 57731400
-
1
tz.transition 1972, 4, :o4, 73459800
-
1
tz.transition 1972, 10, :o3, 89181000
-
1
tz.transition 1973, 4, :o4, 104909400
-
1
tz.transition 1973, 10, :o3, 120630600
-
1
tz.transition 1974, 4, :o4, 136359000
-
1
tz.transition 1974, 10, :o3, 152080200
-
1
tz.transition 1975, 4, :o4, 167808600
-
1
tz.transition 1975, 10, :o3, 183529800
-
1
tz.transition 1976, 4, :o4, 199258200
-
1
tz.transition 1976, 10, :o3, 215584200
-
1
tz.transition 1977, 4, :o4, 230707800
-
1
tz.transition 1977, 10, :o3, 247033800
-
1
tz.transition 1978, 4, :o4, 262762200
-
1
tz.transition 1978, 10, :o3, 278483400
-
1
tz.transition 1979, 4, :o4, 294211800
-
1
tz.transition 1979, 10, :o3, 309933000
-
1
tz.transition 1980, 4, :o4, 325661400
-
1
tz.transition 1980, 10, :o3, 341382600
-
1
tz.transition 1981, 4, :o4, 357111000
-
1
tz.transition 1981, 10, :o3, 372832200
-
1
tz.transition 1982, 4, :o4, 388560600
-
1
tz.transition 1982, 10, :o3, 404886600
-
1
tz.transition 1983, 4, :o4, 420010200
-
1
tz.transition 1983, 10, :o3, 436336200
-
1
tz.transition 1984, 4, :o4, 452064600
-
1
tz.transition 1984, 10, :o3, 467785800
-
1
tz.transition 1985, 4, :o4, 483514200
-
1
tz.transition 1985, 10, :o3, 499235400
-
1
tz.transition 1986, 4, :o4, 514963800
-
1
tz.transition 1986, 10, :o3, 530685000
-
1
tz.transition 1987, 4, :o4, 544591860
-
1
tz.transition 1987, 10, :o3, 562127460
-
1
tz.transition 1988, 4, :o7, 576041460
-
1
tz.transition 1988, 10, :o3, 594178260
-
1
tz.transition 1989, 4, :o4, 607491060
-
1
tz.transition 1989, 10, :o3, 625631460
-
1
tz.transition 1990, 4, :o4, 638940660
-
1
tz.transition 1990, 10, :o3, 657081060
-
1
tz.transition 1991, 4, :o4, 670995060
-
1
tz.transition 1991, 10, :o3, 688530660
-
1
tz.transition 1992, 4, :o4, 702444660
-
1
tz.transition 1992, 10, :o3, 719980260
-
1
tz.transition 1993, 4, :o4, 733894260
-
1
tz.transition 1993, 10, :o3, 752034660
-
1
tz.transition 1994, 4, :o4, 765343860
-
1
tz.transition 1994, 10, :o3, 783484260
-
1
tz.transition 1995, 4, :o4, 796793460
-
1
tz.transition 1995, 10, :o3, 814933860
-
1
tz.transition 1996, 4, :o4, 828847860
-
1
tz.transition 1996, 10, :o3, 846383460
-
1
tz.transition 1997, 4, :o4, 860297460
-
1
tz.transition 1997, 10, :o3, 877833060
-
1
tz.transition 1998, 4, :o4, 891747060
-
1
tz.transition 1998, 10, :o3, 909282660
-
1
tz.transition 1999, 4, :o4, 923196660
-
1
tz.transition 1999, 10, :o3, 941337060
-
1
tz.transition 2000, 4, :o4, 954646260
-
1
tz.transition 2000, 10, :o3, 972786660
-
1
tz.transition 2001, 4, :o4, 986095860
-
1
tz.transition 2001, 10, :o3, 1004236260
-
1
tz.transition 2002, 4, :o4, 1018150260
-
1
tz.transition 2002, 10, :o3, 1035685860
-
1
tz.transition 2003, 4, :o4, 1049599860
-
1
tz.transition 2003, 10, :o3, 1067135460
-
1
tz.transition 2004, 4, :o4, 1081049460
-
1
tz.transition 2004, 10, :o3, 1099189860
-
1
tz.transition 2005, 4, :o4, 1112499060
-
1
tz.transition 2005, 10, :o3, 1130639460
-
1
tz.transition 2006, 4, :o4, 1143948660
-
1
tz.transition 2006, 10, :o3, 1162089060
-
1
tz.transition 2007, 3, :o4, 1173583860
-
1
tz.transition 2007, 11, :o3, 1194143460
-
1
tz.transition 2008, 3, :o4, 1205033460
-
1
tz.transition 2008, 11, :o3, 1225593060
-
1
tz.transition 2009, 3, :o4, 1236483060
-
1
tz.transition 2009, 11, :o3, 1257042660
-
1
tz.transition 2010, 3, :o4, 1268537460
-
1
tz.transition 2010, 11, :o3, 1289097060
-
1
tz.transition 2011, 3, :o4, 1299987060
-
1
tz.transition 2011, 11, :o3, 1320553800
-
1
tz.transition 2012, 3, :o4, 1331443800
-
1
tz.transition 2012, 11, :o3, 1352003400
-
1
tz.transition 2013, 3, :o4, 1362893400
-
1
tz.transition 2013, 11, :o3, 1383453000
-
1
tz.transition 2014, 3, :o4, 1394343000
-
1
tz.transition 2014, 11, :o3, 1414902600
-
1
tz.transition 2015, 3, :o4, 1425792600
-
1
tz.transition 2015, 11, :o3, 1446352200
-
1
tz.transition 2016, 3, :o4, 1457847000
-
1
tz.transition 2016, 11, :o3, 1478406600
-
1
tz.transition 2017, 3, :o4, 1489296600
-
1
tz.transition 2017, 11, :o3, 1509856200
-
1
tz.transition 2018, 3, :o4, 1520746200
-
1
tz.transition 2018, 11, :o3, 1541305800
-
1
tz.transition 2019, 3, :o4, 1552195800
-
1
tz.transition 2019, 11, :o3, 1572755400
-
1
tz.transition 2020, 3, :o4, 1583645400
-
1
tz.transition 2020, 11, :o3, 1604205000
-
1
tz.transition 2021, 3, :o4, 1615699800
-
1
tz.transition 2021, 11, :o3, 1636259400
-
1
tz.transition 2022, 3, :o4, 1647149400
-
1
tz.transition 2022, 11, :o3, 1667709000
-
1
tz.transition 2023, 3, :o4, 1678599000
-
1
tz.transition 2023, 11, :o3, 1699158600
-
1
tz.transition 2024, 3, :o4, 1710048600
-
1
tz.transition 2024, 11, :o3, 1730608200
-
1
tz.transition 2025, 3, :o4, 1741498200
-
1
tz.transition 2025, 11, :o3, 1762057800
-
1
tz.transition 2026, 3, :o4, 1772947800
-
1
tz.transition 2026, 11, :o3, 1793507400
-
1
tz.transition 2027, 3, :o4, 1805002200
-
1
tz.transition 2027, 11, :o3, 1825561800
-
1
tz.transition 2028, 3, :o4, 1836451800
-
1
tz.transition 2028, 11, :o3, 1857011400
-
1
tz.transition 2029, 3, :o4, 1867901400
-
1
tz.transition 2029, 11, :o3, 1888461000
-
1
tz.transition 2030, 3, :o4, 1899351000
-
1
tz.transition 2030, 11, :o3, 1919910600
-
1
tz.transition 2031, 3, :o4, 1930800600
-
1
tz.transition 2031, 11, :o3, 1951360200
-
1
tz.transition 2032, 3, :o4, 1962855000
-
1
tz.transition 2032, 11, :o3, 1983414600
-
1
tz.transition 2033, 3, :o4, 1994304600
-
1
tz.transition 2033, 11, :o3, 2014864200
-
1
tz.transition 2034, 3, :o4, 2025754200
-
1
tz.transition 2034, 11, :o3, 2046313800
-
1
tz.transition 2035, 3, :o4, 2057203800
-
1
tz.transition 2035, 11, :o3, 2077763400
-
1
tz.transition 2036, 3, :o4, 2088653400
-
1
tz.transition 2036, 11, :o3, 2109213000
-
1
tz.transition 2037, 3, :o4, 2120103000
-
1
tz.transition 2037, 11, :o3, 2140662600
-
1
tz.transition 2038, 3, :o4, 118343843, 48
-
1
tz.transition 2038, 11, :o3, 39451755, 16
-
1
tz.transition 2039, 3, :o4, 118361315, 48
-
1
tz.transition 2039, 11, :o3, 39457579, 16
-
1
tz.transition 2040, 3, :o4, 118378787, 48
-
1
tz.transition 2040, 11, :o3, 39463403, 16
-
1
tz.transition 2041, 3, :o4, 118396259, 48
-
1
tz.transition 2041, 11, :o3, 39469227, 16
-
1
tz.transition 2042, 3, :o4, 118413731, 48
-
1
tz.transition 2042, 11, :o3, 39475051, 16
-
1
tz.transition 2043, 3, :o4, 118431203, 48
-
1
tz.transition 2043, 11, :o3, 39480875, 16
-
1
tz.transition 2044, 3, :o4, 118449011, 48
-
1
tz.transition 2044, 11, :o3, 39486811, 16
-
1
tz.transition 2045, 3, :o4, 118466483, 48
-
1
tz.transition 2045, 11, :o3, 39492635, 16
-
1
tz.transition 2046, 3, :o4, 118483955, 48
-
1
tz.transition 2046, 11, :o3, 39498459, 16
-
1
tz.transition 2047, 3, :o4, 118501427, 48
-
1
tz.transition 2047, 11, :o3, 39504283, 16
-
1
tz.transition 2048, 3, :o4, 118518899, 48
-
1
tz.transition 2048, 11, :o3, 39510107, 16
-
1
tz.transition 2049, 3, :o4, 118536707, 48
-
1
tz.transition 2049, 11, :o3, 39516043, 16
-
1
tz.transition 2050, 3, :o4, 118554179, 48
-
1
tz.transition 2050, 11, :o3, 39521867, 16
-
end
-
end
-
end
-
end
-
end
-
1
module TZInfo
-
1
module Definitions
-
1
module America
-
1
module Tijuana
-
1
include TimezoneDefinition
-
-
1
timezone 'America/Tijuana' do |tz|
-
1
tz.offset :o0, -28084, 0, :LMT
-
1
tz.offset :o1, -25200, 0, :MST
-
1
tz.offset :o2, -28800, 0, :PST
-
1
tz.offset :o3, -28800, 3600, :PDT
-
1
tz.offset :o4, -28800, 3600, :PWT
-
1
tz.offset :o5, -28800, 3600, :PPT
-
-
1
tz.transition 1922, 1, :o1, 14538335, 6
-
1
tz.transition 1924, 1, :o2, 58170859, 24
-
1
tz.transition 1927, 6, :o1, 58201027, 24
-
1
tz.transition 1930, 11, :o2, 58231099, 24
-
1
tz.transition 1931, 4, :o3, 14558597, 6
-
1
tz.transition 1931, 9, :o2, 58238755, 24
-
1
tz.transition 1942, 4, :o4, 14582843, 6
-
1
tz.transition 1945, 8, :o5, 58360379, 24
-
1
tz.transition 1945, 11, :o2, 58362523, 24
-
1
tz.transition 1948, 4, :o3, 14595881, 6
-
1
tz.transition 1949, 1, :o2, 58390339, 24
-
1
tz.transition 1954, 4, :o3, 29218295, 12
-
1
tz.transition 1954, 9, :o2, 19480095, 8
-
1
tz.transition 1955, 4, :o3, 29222663, 12
-
1
tz.transition 1955, 9, :o2, 19483007, 8
-
1
tz.transition 1956, 4, :o3, 29227115, 12
-
1
tz.transition 1956, 9, :o2, 19485975, 8
-
1
tz.transition 1957, 4, :o3, 29231483, 12
-
1
tz.transition 1957, 9, :o2, 19488887, 8
-
1
tz.transition 1958, 4, :o3, 29235851, 12
-
1
tz.transition 1958, 9, :o2, 19491799, 8
-
1
tz.transition 1959, 4, :o3, 29240219, 12
-
1
tz.transition 1959, 9, :o2, 19494711, 8
-
1
tz.transition 1960, 4, :o3, 29244587, 12
-
1
tz.transition 1960, 9, :o2, 19497623, 8
-
1
tz.transition 1976, 4, :o3, 199274400
-
1
tz.transition 1976, 10, :o2, 215600400
-
1
tz.transition 1977, 4, :o3, 230724000
-
1
tz.transition 1977, 10, :o2, 247050000
-
1
tz.transition 1978, 4, :o3, 262778400
-
1
tz.transition 1978, 10, :o2, 278499600
-
1
tz.transition 1979, 4, :o3, 294228000
-
1
tz.transition 1979, 10, :o2, 309949200
-
1
tz.transition 1980, 4, :o3, 325677600
-
1
tz.transition 1980, 10, :o2, 341398800
-
1
tz.transition 1981, 4, :o3, 357127200
-
1
tz.transition 1981, 10, :o2, 372848400
-
1
tz.transition 1982, 4, :o3, 388576800
-
1
tz.transition 1982, 10, :o2, 404902800
-
1
tz.transition 1983, 4, :o3, 420026400
-
1
tz.transition 1983, 10, :o2, 436352400
-
1
tz.transition 1984, 4, :o3, 452080800
-
1
tz.transition 1984, 10, :o2, 467802000
-
1
tz.transition 1985, 4, :o3, 483530400
-
1
tz.transition 1985, 10, :o2, 499251600
-
1
tz.transition 1986, 4, :o3, 514980000
-
1
tz.transition 1986, 10, :o2, 530701200
-
1
tz.transition 1987, 4, :o3, 544615200
-
1
tz.transition 1987, 10, :o2, 562150800
-
1
tz.transition 1988, 4, :o3, 576064800
-
1
tz.transition 1988, 10, :o2, 594205200
-
1
tz.transition 1989, 4, :o3, 607514400
-
1
tz.transition 1989, 10, :o2, 625654800
-
1
tz.transition 1990, 4, :o3, 638964000
-
1
tz.transition 1990, 10, :o2, 657104400
-
1
tz.transition 1991, 4, :o3, 671018400
-
1
tz.transition 1991, 10, :o2, 688554000
-
1
tz.transition 1992, 4, :o3, 702468000
-
1
tz.transition 1992, 10, :o2, 720003600
-
1
tz.transition 1993, 4, :o3, 733917600
-
1
tz.transition 1993, 10, :o2, 752058000
-
1
tz.transition 1994, 4, :o3, 765367200
-
1
tz.transition 1994, 10, :o2, 783507600
-
1
tz.transition 1995, 4, :o3, 796816800
-
1
tz.transition 1995, 10, :o2, 814957200
-
1
tz.transition 1996, 4, :o3, 828871200
-
1
tz.transition 1996, 10, :o2, 846406800
-
1
tz.transition 1997, 4, :o3, 860320800
-
1
tz.transition 1997, 10, :o2, 877856400
-
1
tz.transition 1998, 4, :o3, 891770400
-
1
tz.transition 1998, 10, :o2, 909306000
-
1
tz.transition 1999, 4, :o3, 923220000
-
1
tz.transition 1999, 10, :o2, 941360400
-
1
tz.transition 2000, 4, :o3, 954669600
-
1
tz.transition 2000, 10, :o2, 972810000
-
1
tz.transition 2001, 4, :o3, 986119200
-
1
tz.transition 2001, 10, :o2, 1004259600
-
1
tz.transition 2002, 4, :o3, 1018173600
-
1
tz.transition 2002, 10, :o2, 1035709200
-
1
tz.transition 2003, 4, :o3, 1049623200
-
1
tz.transition 2003, 10, :o2, 1067158800
-
1
tz.transition 2004, 4, :o3, 1081072800
-
1
tz.transition 2004, 10, :o2, 1099213200
-
1
tz.transition 2005, 4, :o3, 1112522400
-
1
tz.transition 2005, 10, :o2, 1130662800
-
1
tz.transition 2006, 4, :o3, 1143972000
-
1
tz.transition 2006, 10, :o2, 1162112400
-
1
tz.transition 2007, 4, :o3, 1175421600
-
1
tz.transition 2007, 10, :o2, 1193562000
-
1
tz.transition 2008, 4, :o3, 1207476000
-
1
tz.transition 2008, 10, :o2, 1225011600
-
1
tz.transition 2009, 4, :o3, 1238925600
-
1
tz.transition 2009, 10, :o2, 1256461200
-
1
tz.transition 2010, 3, :o3, 1268560800
-
1
tz.transition 2010, 11, :o2, 1289120400
-
1
tz.transition 2011, 3, :o3, 1300010400
-
1
tz.transition 2011, 11, :o2, 1320570000
-
1
tz.transition 2012, 3, :o3, 1331460000
-
1
tz.transition 2012, 11, :o2, 1352019600
-
1
tz.transition 2013, 3, :o3, 1362909600
-
1
tz.transition 2013, 11, :o2, 1383469200
-
1
tz.transition 2014, 3, :o3, 1394359200
-
1
tz.transition 2014, 11, :o2, 1414918800
-
1
tz.transition 2015, 3, :o3, 1425808800
-
1
tz.transition 2015, 11, :o2, 1446368400
-
1
tz.transition 2016, 3, :o3, 1457863200
-
1
tz.transition 2016, 11, :o2, 1478422800
-
1
tz.transition 2017, 3, :o3, 1489312800
-
1
tz.transition 2017, 11, :o2, 1509872400
-
1
tz.transition 2018, 3, :o3, 1520762400
-
1
tz.transition 2018, 11, :o2, 1541322000
-
1
tz.transition 2019, 3, :o3, 1552212000
-
1
tz.transition 2019, 11, :o2, 1572771600
-
1
tz.transition 2020, 3, :o3, 1583661600
-
1
tz.transition 2020, 11, :o2, 1604221200
-
1
tz.transition 2021, 3, :o3, 1615716000
-
1
tz.transition 2021, 11, :o2, 1636275600
-
1
tz.transition 2022, 3, :o3, 1647165600
-
1
tz.transition 2022, 11, :o2, 1667725200
-
1
tz.transition 2023, 3, :o3, 1678615200
-
1
tz.transition 2023, 11, :o2, 1699174800
-
1
tz.transition 2024, 3, :o3, 1710064800
-
1
tz.transition 2024, 11, :o2, 1730624400
-
1
tz.transition 2025, 3, :o3, 1741514400
-
1
tz.transition 2025, 11, :o2, 1762074000
-
1
tz.transition 2026, 3, :o3, 1772964000
-
1
tz.transition 2026, 11, :o2, 1793523600
-
1
tz.transition 2027, 3, :o3, 1805018400
-
1
tz.transition 2027, 11, :o2, 1825578000
-
1
tz.transition 2028, 3, :o3, 1836468000
-
1
tz.transition 2028, 11, :o2, 1857027600
-
1
tz.transition 2029, 3, :o3, 1867917600
-
1
tz.transition 2029, 11, :o2, 1888477200
-
1
tz.transition 2030, 3, :o3, 1899367200
-
1
tz.transition 2030, 11, :o2, 1919926800
-
1
tz.transition 2031, 3, :o3, 1930816800
-
1
tz.transition 2031, 11, :o2, 1951376400
-
1
tz.transition 2032, 3, :o3, 1962871200
-
1
tz.transition 2032, 11, :o2, 1983430800
-
1
tz.transition 2033, 3, :o3, 1994320800
-
1
tz.transition 2033, 11, :o2, 2014880400
-
1
tz.transition 2034, 3, :o3, 2025770400
-
1
tz.transition 2034, 11, :o2, 2046330000
-
1
tz.transition 2035, 3, :o3, 2057220000
-
1
tz.transition 2035, 11, :o2, 2077779600
-
1
tz.transition 2036, 3, :o3, 2088669600
-
1
tz.transition 2036, 11, :o2, 2109229200
-
1
tz.transition 2037, 3, :o3, 2120119200
-
1
tz.transition 2037, 11, :o2, 2140678800
-
1
tz.transition 2038, 3, :o3, 29585963, 12
-
1
tz.transition 2038, 11, :o2, 19725879, 8
-
1
tz.transition 2039, 3, :o3, 29590331, 12
-
1
tz.transition 2039, 11, :o2, 19728791, 8
-
1
tz.transition 2040, 3, :o3, 29594699, 12
-
1
tz.transition 2040, 11, :o2, 19731703, 8
-
1
tz.transition 2041, 3, :o3, 29599067, 12
-
1
tz.transition 2041, 11, :o2, 19734615, 8
-
1
tz.transition 2042, 3, :o3, 29603435, 12
-
1
tz.transition 2042, 11, :o2, 19737527, 8
-
1
tz.transition 2043, 3, :o3, 29607803, 12
-
1
tz.transition 2043, 11, :o2, 19740439, 8
-
1
tz.transition 2044, 3, :o3, 29612255, 12
-
1
tz.transition 2044, 11, :o2, 19743407, 8
-
1
tz.transition 2045, 3, :o3, 29616623, 12
-
1
tz.transition 2045, 11, :o2, 19746319, 8
-
1
tz.transition 2046, 3, :o3, 29620991, 12
-
1
tz.transition 2046, 11, :o2, 19749231, 8
-
1
tz.transition 2047, 3, :o3, 29625359, 12
-
1
tz.transition 2047, 11, :o2, 19752143, 8
-
1
tz.transition 2048, 3, :o3, 29629727, 12
-
1
tz.transition 2048, 11, :o2, 19755055, 8
-
1
tz.transition 2049, 3, :o3, 29634179, 12
-
1
tz.transition 2049, 11, :o2, 19758023, 8
-
1
tz.transition 2050, 3, :o3, 29638547, 12
-
1
tz.transition 2050, 11, :o2, 19760935, 8
-
end
-
end
-
end
-
end
-
end
-
1
module TZInfo
-
1
module Definitions
-
1
module Asia
-
1
module Almaty
-
1
include TimezoneDefinition
-
-
1
timezone 'Asia/Almaty' do |tz|
-
1
tz.offset :o0, 18468, 0, :LMT
-
1
tz.offset :o1, 18000, 0, :ALMT
-
1
tz.offset :o2, 21600, 0, :ALMT
-
1
tz.offset :o3, 21600, 3600, :ALMST
-
-
1
tz.transition 1924, 5, :o1, 1939125829, 800
-
1
tz.transition 1930, 6, :o2, 58227559, 24
-
1
tz.transition 1981, 3, :o3, 354909600
-
1
tz.transition 1981, 9, :o2, 370717200
-
1
tz.transition 1982, 3, :o3, 386445600
-
1
tz.transition 1982, 9, :o2, 402253200
-
1
tz.transition 1983, 3, :o3, 417981600
-
1
tz.transition 1983, 9, :o2, 433789200
-
1
tz.transition 1984, 3, :o3, 449604000
-
1
tz.transition 1984, 9, :o2, 465336000
-
1
tz.transition 1985, 3, :o3, 481060800
-
1
tz.transition 1985, 9, :o2, 496785600
-
1
tz.transition 1986, 3, :o3, 512510400
-
1
tz.transition 1986, 9, :o2, 528235200
-
1
tz.transition 1987, 3, :o3, 543960000
-
1
tz.transition 1987, 9, :o2, 559684800
-
1
tz.transition 1988, 3, :o3, 575409600
-
1
tz.transition 1988, 9, :o2, 591134400
-
1
tz.transition 1989, 3, :o3, 606859200
-
1
tz.transition 1989, 9, :o2, 622584000
-
1
tz.transition 1990, 3, :o3, 638308800
-
1
tz.transition 1990, 9, :o2, 654638400
-
1
tz.transition 1992, 3, :o3, 701802000
-
1
tz.transition 1992, 9, :o2, 717523200
-
1
tz.transition 1993, 3, :o3, 733262400
-
1
tz.transition 1993, 9, :o2, 748987200
-
1
tz.transition 1994, 3, :o3, 764712000
-
1
tz.transition 1994, 9, :o2, 780436800
-
1
tz.transition 1995, 3, :o3, 796161600
-
1
tz.transition 1995, 9, :o2, 811886400
-
1
tz.transition 1996, 3, :o3, 828216000
-
1
tz.transition 1996, 10, :o2, 846360000
-
1
tz.transition 1997, 3, :o3, 859665600
-
1
tz.transition 1997, 10, :o2, 877809600
-
1
tz.transition 1998, 3, :o3, 891115200
-
1
tz.transition 1998, 10, :o2, 909259200
-
1
tz.transition 1999, 3, :o3, 922564800
-
1
tz.transition 1999, 10, :o2, 941313600
-
1
tz.transition 2000, 3, :o3, 954014400
-
1
tz.transition 2000, 10, :o2, 972763200
-
1
tz.transition 2001, 3, :o3, 985464000
-
1
tz.transition 2001, 10, :o2, 1004212800
-
1
tz.transition 2002, 3, :o3, 1017518400
-
1
tz.transition 2002, 10, :o2, 1035662400
-
1
tz.transition 2003, 3, :o3, 1048968000
-
1
tz.transition 2003, 10, :o2, 1067112000
-
1
tz.transition 2004, 3, :o3, 1080417600
-
1
tz.transition 2004, 10, :o2, 1099166400
-
end
-
end
-
end
-
end
-
end
-
1
module TZInfo
-
1
module Definitions
-
1
module Asia
-
1
module Baghdad
-
1
include TimezoneDefinition
-
-
1
timezone 'Asia/Baghdad' do |tz|
-
1
tz.offset :o0, 10660, 0, :LMT
-
1
tz.offset :o1, 10656, 0, :BMT
-
1
tz.offset :o2, 10800, 0, :AST
-
1
tz.offset :o3, 10800, 3600, :ADT
-
-
1
tz.transition 1889, 12, :o1, 10417111387, 4320
-
1
tz.transition 1917, 12, :o2, 726478313, 300
-
1
tz.transition 1982, 4, :o3, 389048400
-
1
tz.transition 1982, 9, :o2, 402264000
-
1
tz.transition 1983, 3, :o3, 417906000
-
1
tz.transition 1983, 9, :o2, 433800000
-
1
tz.transition 1984, 3, :o3, 449614800
-
1
tz.transition 1984, 9, :o2, 465422400
-
1
tz.transition 1985, 3, :o3, 481150800
-
1
tz.transition 1985, 9, :o2, 496792800
-
1
tz.transition 1986, 3, :o3, 512517600
-
1
tz.transition 1986, 9, :o2, 528242400
-
1
tz.transition 1987, 3, :o3, 543967200
-
1
tz.transition 1987, 9, :o2, 559692000
-
1
tz.transition 1988, 3, :o3, 575416800
-
1
tz.transition 1988, 9, :o2, 591141600
-
1
tz.transition 1989, 3, :o3, 606866400
-
1
tz.transition 1989, 9, :o2, 622591200
-
1
tz.transition 1990, 3, :o3, 638316000
-
1
tz.transition 1990, 9, :o2, 654645600
-
1
tz.transition 1991, 4, :o3, 670464000
-
1
tz.transition 1991, 10, :o2, 686275200
-
1
tz.transition 1992, 4, :o3, 702086400
-
1
tz.transition 1992, 10, :o2, 717897600
-
1
tz.transition 1993, 4, :o3, 733622400
-
1
tz.transition 1993, 10, :o2, 749433600
-
1
tz.transition 1994, 4, :o3, 765158400
-
1
tz.transition 1994, 10, :o2, 780969600
-
1
tz.transition 1995, 4, :o3, 796694400
-
1
tz.transition 1995, 10, :o2, 812505600
-
1
tz.transition 1996, 4, :o3, 828316800
-
1
tz.transition 1996, 10, :o2, 844128000
-
1
tz.transition 1997, 4, :o3, 859852800
-
1
tz.transition 1997, 10, :o2, 875664000
-
1
tz.transition 1998, 4, :o3, 891388800
-
1
tz.transition 1998, 10, :o2, 907200000
-
1
tz.transition 1999, 4, :o3, 922924800
-
1
tz.transition 1999, 10, :o2, 938736000
-
1
tz.transition 2000, 4, :o3, 954547200
-
1
tz.transition 2000, 10, :o2, 970358400
-
1
tz.transition 2001, 4, :o3, 986083200
-
1
tz.transition 2001, 10, :o2, 1001894400
-
1
tz.transition 2002, 4, :o3, 1017619200
-
1
tz.transition 2002, 10, :o2, 1033430400
-
1
tz.transition 2003, 4, :o3, 1049155200
-
1
tz.transition 2003, 10, :o2, 1064966400
-
1
tz.transition 2004, 4, :o3, 1080777600
-
1
tz.transition 2004, 10, :o2, 1096588800
-
1
tz.transition 2005, 4, :o3, 1112313600
-
1
tz.transition 2005, 10, :o2, 1128124800
-
1
tz.transition 2006, 4, :o3, 1143849600
-
1
tz.transition 2006, 10, :o2, 1159660800
-
1
tz.transition 2007, 4, :o3, 1175385600
-
1
tz.transition 2007, 10, :o2, 1191196800
-
end
-
end
-
end
-
end
-
end
-
1
module TZInfo
-
1
module Definitions
-
1
module Asia
-
1
module Baku
-
1
include TimezoneDefinition
-
-
1
timezone 'Asia/Baku' do |tz|
-
1
tz.offset :o0, 11964, 0, :LMT
-
1
tz.offset :o1, 10800, 0, :BAKT
-
1
tz.offset :o2, 14400, 0, :BAKT
-
1
tz.offset :o3, 14400, 3600, :BAKST
-
1
tz.offset :o4, 10800, 3600, :BAKST
-
1
tz.offset :o5, 10800, 3600, :AZST
-
1
tz.offset :o6, 10800, 0, :AZT
-
1
tz.offset :o7, 14400, 0, :AZT
-
1
tz.offset :o8, 14400, 3600, :AZST
-
-
1
tz.transition 1924, 5, :o1, 17452133003, 7200
-
1
tz.transition 1957, 2, :o2, 19487187, 8
-
1
tz.transition 1981, 3, :o3, 354916800
-
1
tz.transition 1981, 9, :o2, 370724400
-
1
tz.transition 1982, 3, :o3, 386452800
-
1
tz.transition 1982, 9, :o2, 402260400
-
1
tz.transition 1983, 3, :o3, 417988800
-
1
tz.transition 1983, 9, :o2, 433796400
-
1
tz.transition 1984, 3, :o3, 449611200
-
1
tz.transition 1984, 9, :o2, 465343200
-
1
tz.transition 1985, 3, :o3, 481068000
-
1
tz.transition 1985, 9, :o2, 496792800
-
1
tz.transition 1986, 3, :o3, 512517600
-
1
tz.transition 1986, 9, :o2, 528242400
-
1
tz.transition 1987, 3, :o3, 543967200
-
1
tz.transition 1987, 9, :o2, 559692000
-
1
tz.transition 1988, 3, :o3, 575416800
-
1
tz.transition 1988, 9, :o2, 591141600
-
1
tz.transition 1989, 3, :o3, 606866400
-
1
tz.transition 1989, 9, :o2, 622591200
-
1
tz.transition 1990, 3, :o3, 638316000
-
1
tz.transition 1990, 9, :o2, 654645600
-
1
tz.transition 1991, 3, :o4, 670370400
-
1
tz.transition 1991, 8, :o5, 683496000
-
1
tz.transition 1991, 9, :o6, 686098800
-
1
tz.transition 1992, 3, :o5, 701812800
-
1
tz.transition 1992, 9, :o7, 717534000
-
1
tz.transition 1996, 3, :o8, 828234000
-
1
tz.transition 1996, 10, :o7, 846378000
-
1
tz.transition 1997, 3, :o8, 859680000
-
1
tz.transition 1997, 10, :o7, 877824000
-
1
tz.transition 1998, 3, :o8, 891129600
-
1
tz.transition 1998, 10, :o7, 909273600
-
1
tz.transition 1999, 3, :o8, 922579200
-
1
tz.transition 1999, 10, :o7, 941328000
-
1
tz.transition 2000, 3, :o8, 954028800
-
1
tz.transition 2000, 10, :o7, 972777600
-
1
tz.transition 2001, 3, :o8, 985478400
-
1
tz.transition 2001, 10, :o7, 1004227200
-
1
tz.transition 2002, 3, :o8, 1017532800
-
1
tz.transition 2002, 10, :o7, 1035676800
-
1
tz.transition 2003, 3, :o8, 1048982400
-
1
tz.transition 2003, 10, :o7, 1067126400
-
1
tz.transition 2004, 3, :o8, 1080432000
-
1
tz.transition 2004, 10, :o7, 1099180800
-
1
tz.transition 2005, 3, :o8, 1111881600
-
1
tz.transition 2005, 10, :o7, 1130630400
-
1
tz.transition 2006, 3, :o8, 1143331200
-
1
tz.transition 2006, 10, :o7, 1162080000
-
1
tz.transition 2007, 3, :o8, 1174780800
-
1
tz.transition 2007, 10, :o7, 1193529600
-
1
tz.transition 2008, 3, :o8, 1206835200
-
1
tz.transition 2008, 10, :o7, 1224979200
-
1
tz.transition 2009, 3, :o8, 1238284800
-
1
tz.transition 2009, 10, :o7, 1256428800
-
1
tz.transition 2010, 3, :o8, 1269734400
-
1
tz.transition 2010, 10, :o7, 1288483200
-
1
tz.transition 2011, 3, :o8, 1301184000
-
1
tz.transition 2011, 10, :o7, 1319932800
-
1
tz.transition 2012, 3, :o8, 1332633600
-
1
tz.transition 2012, 10, :o7, 1351382400
-
1
tz.transition 2013, 3, :o8, 1364688000
-
1
tz.transition 2013, 10, :o7, 1382832000
-
1
tz.transition 2014, 3, :o8, 1396137600
-
1
tz.transition 2014, 10, :o7, 1414281600
-
1
tz.transition 2015, 3, :o8, 1427587200
-
1
tz.transition 2015, 10, :o7, 1445731200
-
1
tz.transition 2016, 3, :o8, 1459036800
-
1
tz.transition 2016, 10, :o7, 1477785600
-
1
tz.transition 2017, 3, :o8, 1490486400
-
1
tz.transition 2017, 10, :o7, 1509235200
-
1
tz.transition 2018, 3, :o8, 1521936000
-
1
tz.transition 2018, 10, :o7, 1540684800
-
1
tz.transition 2019, 3, :o8, 1553990400
-
1
tz.transition 2019, 10, :o7, 1572134400
-
1
tz.transition 2020, 3, :o8, 1585440000
-
1
tz.transition 2020, 10, :o7, 1603584000
-
1
tz.transition 2021, 3, :o8, 1616889600
-
1
tz.transition 2021, 10, :o7, 1635638400
-
1
tz.transition 2022, 3, :o8, 1648339200
-
1
tz.transition 2022, 10, :o7, 1667088000
-
1
tz.transition 2023, 3, :o8, 1679788800
-
1
tz.transition 2023, 10, :o7, 1698537600
-
1
tz.transition 2024, 3, :o8, 1711843200
-
1
tz.transition 2024, 10, :o7, 1729987200
-
1
tz.transition 2025, 3, :o8, 1743292800
-
1
tz.transition 2025, 10, :o7, 1761436800
-
1
tz.transition 2026, 3, :o8, 1774742400
-
1
tz.transition 2026, 10, :o7, 1792886400
-
1
tz.transition 2027, 3, :o8, 1806192000
-
1
tz.transition 2027, 10, :o7, 1824940800
-
1
tz.transition 2028, 3, :o8, 1837641600
-
1
tz.transition 2028, 10, :o7, 1856390400
-
1
tz.transition 2029, 3, :o8, 1869091200
-
1
tz.transition 2029, 10, :o7, 1887840000
-
1
tz.transition 2030, 3, :o8, 1901145600
-
1
tz.transition 2030, 10, :o7, 1919289600
-
1
tz.transition 2031, 3, :o8, 1932595200
-
1
tz.transition 2031, 10, :o7, 1950739200
-
1
tz.transition 2032, 3, :o8, 1964044800
-
1
tz.transition 2032, 10, :o7, 1982793600
-
1
tz.transition 2033, 3, :o8, 1995494400
-
1
tz.transition 2033, 10, :o7, 2014243200
-
1
tz.transition 2034, 3, :o8, 2026944000
-
1
tz.transition 2034, 10, :o7, 2045692800
-
1
tz.transition 2035, 3, :o8, 2058393600
-
1
tz.transition 2035, 10, :o7, 2077142400
-
1
tz.transition 2036, 3, :o8, 2090448000
-
1
tz.transition 2036, 10, :o7, 2108592000
-
1
tz.transition 2037, 3, :o8, 2121897600
-
1
tz.transition 2037, 10, :o7, 2140041600
-
1
tz.transition 2038, 3, :o8, 4931021, 2
-
1
tz.transition 2038, 10, :o7, 4931455, 2
-
1
tz.transition 2039, 3, :o8, 4931749, 2
-
1
tz.transition 2039, 10, :o7, 4932183, 2
-
1
tz.transition 2040, 3, :o8, 4932477, 2
-
1
tz.transition 2040, 10, :o7, 4932911, 2
-
1
tz.transition 2041, 3, :o8, 4933219, 2
-
1
tz.transition 2041, 10, :o7, 4933639, 2
-
1
tz.transition 2042, 3, :o8, 4933947, 2
-
1
tz.transition 2042, 10, :o7, 4934367, 2
-
1
tz.transition 2043, 3, :o8, 4934675, 2
-
1
tz.transition 2043, 10, :o7, 4935095, 2
-
1
tz.transition 2044, 3, :o8, 4935403, 2
-
1
tz.transition 2044, 10, :o7, 4935837, 2
-
1
tz.transition 2045, 3, :o8, 4936131, 2
-
1
tz.transition 2045, 10, :o7, 4936565, 2
-
1
tz.transition 2046, 3, :o8, 4936859, 2
-
1
tz.transition 2046, 10, :o7, 4937293, 2
-
1
tz.transition 2047, 3, :o8, 4937601, 2
-
1
tz.transition 2047, 10, :o7, 4938021, 2
-
1
tz.transition 2048, 3, :o8, 4938329, 2
-
1
tz.transition 2048, 10, :o7, 4938749, 2
-
1
tz.transition 2049, 3, :o8, 4939057, 2
-
1
tz.transition 2049, 10, :o7, 4939491, 2
-
1
tz.transition 2050, 3, :o8, 4939785, 2
-
1
tz.transition 2050, 10, :o7, 4940219, 2
-
end
-
end
-
end
-
end
-
end
-
1
module TZInfo
-
1
module Definitions
-
1
module Asia
-
1
module Bangkok
-
1
include TimezoneDefinition
-
-
1
timezone 'Asia/Bangkok' do |tz|
-
1
tz.offset :o0, 24124, 0, :LMT
-
1
tz.offset :o1, 24124, 0, :BMT
-
1
tz.offset :o2, 25200, 0, :ICT
-
-
1
tz.transition 1879, 12, :o1, 52006648769, 21600
-
1
tz.transition 1920, 3, :o2, 52324168769, 21600
-
end
-
end
-
end
-
end
-
end
-
1
module TZInfo
-
1
module Definitions
-
1
module Asia
-
1
module Chongqing
-
1
include TimezoneDefinition
-
-
1
timezone 'Asia/Chongqing' do |tz|
-
1
tz.offset :o0, 25580, 0, :LMT
-
1
tz.offset :o1, 25200, 0, :LONT
-
1
tz.offset :o2, 28800, 0, :CST
-
1
tz.offset :o3, 28800, 3600, :CDT
-
-
1
tz.transition 1927, 12, :o1, 10477063601, 4320
-
1
tz.transition 1980, 4, :o2, 325962000
-
1
tz.transition 1986, 5, :o3, 515520000
-
1
tz.transition 1986, 9, :o2, 527007600
-
1
tz.transition 1987, 4, :o3, 545155200
-
1
tz.transition 1987, 9, :o2, 558457200
-
1
tz.transition 1988, 4, :o3, 576604800
-
1
tz.transition 1988, 9, :o2, 589906800
-
1
tz.transition 1989, 4, :o3, 608659200
-
1
tz.transition 1989, 9, :o2, 621961200
-
1
tz.transition 1990, 4, :o3, 640108800
-
1
tz.transition 1990, 9, :o2, 653410800
-
1
tz.transition 1991, 4, :o3, 671558400
-
1
tz.transition 1991, 9, :o2, 684860400
-
end
-
end
-
end
-
end
-
end
-
1
module TZInfo
-
1
module Definitions
-
1
module Asia
-
1
module Colombo
-
1
include TimezoneDefinition
-
-
1
timezone 'Asia/Colombo' do |tz|
-
1
tz.offset :o0, 19164, 0, :LMT
-
1
tz.offset :o1, 19172, 0, :MMT
-
1
tz.offset :o2, 19800, 0, :IST
-
1
tz.offset :o3, 19800, 1800, :IHST
-
1
tz.offset :o4, 19800, 3600, :IST
-
1
tz.offset :o5, 23400, 0, :LKT
-
1
tz.offset :o6, 21600, 0, :LKT
-
-
1
tz.transition 1879, 12, :o1, 17335550003, 7200
-
1
tz.transition 1905, 12, :o2, 52211763607, 21600
-
1
tz.transition 1942, 1, :o3, 116657485, 48
-
1
tz.transition 1942, 8, :o4, 9722413, 4
-
1
tz.transition 1945, 10, :o2, 38907909, 16
-
1
tz.transition 1996, 5, :o5, 832962600
-
1
tz.transition 1996, 10, :o6, 846266400
-
1
tz.transition 2006, 4, :o2, 1145039400
-
end
-
end
-
end
-
end
-
end
-
1
module TZInfo
-
1
module Definitions
-
1
module Asia
-
1
module Dhaka
-
1
include TimezoneDefinition
-
-
1
timezone 'Asia/Dhaka' do |tz|
-
1
tz.offset :o0, 21700, 0, :LMT
-
1
tz.offset :o1, 21200, 0, :HMT
-
1
tz.offset :o2, 23400, 0, :BURT
-
1
tz.offset :o3, 19800, 0, :IST
-
1
tz.offset :o4, 21600, 0, :DACT
-
1
tz.offset :o5, 21600, 0, :BDT
-
1
tz.offset :o6, 21600, 3600, :BDST
-
-
1
tz.transition 1889, 12, :o1, 2083422167, 864
-
1
tz.transition 1941, 9, :o2, 524937943, 216
-
1
tz.transition 1942, 5, :o3, 116663723, 48
-
1
tz.transition 1942, 8, :o2, 116668957, 48
-
1
tz.transition 1951, 9, :o4, 116828123, 48
-
1
tz.transition 1971, 3, :o5, 38772000
-
1
tz.transition 2009, 6, :o6, 1245430800
-
1
tz.transition 2009, 12, :o5, 1262278740
-
end
-
end
-
end
-
end
-
end
-
1
module TZInfo
-
1
module Definitions
-
1
module Asia
-
1
module Hong_Kong
-
1
include TimezoneDefinition
-
-
1
timezone 'Asia/Hong_Kong' do |tz|
-
1
tz.offset :o0, 27396, 0, :LMT
-
1
tz.offset :o1, 28800, 0, :HKT
-
1
tz.offset :o2, 28800, 3600, :HKST
-
1
tz.offset :o3, 32400, 0, :JST
-
-
1
tz.transition 1904, 10, :o1, 5800279639, 2400
-
1
tz.transition 1941, 3, :o2, 38881365, 16
-
1
tz.transition 1941, 9, :o1, 116652829, 48
-
1
tz.transition 1941, 12, :o3, 14582119, 6
-
1
tz.transition 1945, 9, :o1, 19453705, 8
-
1
tz.transition 1946, 4, :o2, 38910885, 16
-
1
tz.transition 1946, 11, :o1, 116743453, 48
-
1
tz.transition 1947, 4, :o2, 38916613, 16
-
1
tz.transition 1947, 12, :o1, 116762365, 48
-
1
tz.transition 1948, 5, :o2, 38922773, 16
-
1
tz.transition 1948, 10, :o1, 116777053, 48
-
1
tz.transition 1949, 4, :o2, 38928149, 16
-
1
tz.transition 1949, 10, :o1, 116794525, 48
-
1
tz.transition 1950, 4, :o2, 38933973, 16
-
1
tz.transition 1950, 10, :o1, 116811997, 48
-
1
tz.transition 1951, 3, :o2, 38939797, 16
-
1
tz.transition 1951, 10, :o1, 116829469, 48
-
1
tz.transition 1952, 4, :o2, 38945733, 16
-
1
tz.transition 1952, 10, :o1, 116846893, 48
-
1
tz.transition 1953, 4, :o2, 38951557, 16
-
1
tz.transition 1953, 10, :o1, 116864749, 48
-
1
tz.transition 1954, 3, :o2, 38957157, 16
-
1
tz.transition 1954, 10, :o1, 116882221, 48
-
1
tz.transition 1955, 3, :o2, 38962981, 16
-
1
tz.transition 1955, 11, :o1, 116900029, 48
-
1
tz.transition 1956, 3, :o2, 38968805, 16
-
1
tz.transition 1956, 11, :o1, 116917501, 48
-
1
tz.transition 1957, 3, :o2, 38974741, 16
-
1
tz.transition 1957, 11, :o1, 116934973, 48
-
1
tz.transition 1958, 3, :o2, 38980565, 16
-
1
tz.transition 1958, 11, :o1, 116952445, 48
-
1
tz.transition 1959, 3, :o2, 38986389, 16
-
1
tz.transition 1959, 10, :o1, 116969917, 48
-
1
tz.transition 1960, 3, :o2, 38992213, 16
-
1
tz.transition 1960, 11, :o1, 116987725, 48
-
1
tz.transition 1961, 3, :o2, 38998037, 16
-
1
tz.transition 1961, 11, :o1, 117005197, 48
-
1
tz.transition 1962, 3, :o2, 39003861, 16
-
1
tz.transition 1962, 11, :o1, 117022669, 48
-
1
tz.transition 1963, 3, :o2, 39009797, 16
-
1
tz.transition 1963, 11, :o1, 117040141, 48
-
1
tz.transition 1964, 3, :o2, 39015621, 16
-
1
tz.transition 1964, 10, :o1, 117057613, 48
-
1
tz.transition 1965, 4, :o2, 39021893, 16
-
1
tz.transition 1965, 10, :o1, 117074413, 48
-
1
tz.transition 1966, 4, :o2, 39027717, 16
-
1
tz.transition 1966, 10, :o1, 117091885, 48
-
1
tz.transition 1967, 4, :o2, 39033541, 16
-
1
tz.transition 1967, 10, :o1, 117109693, 48
-
1
tz.transition 1968, 4, :o2, 39039477, 16
-
1
tz.transition 1968, 10, :o1, 117127165, 48
-
1
tz.transition 1969, 4, :o2, 39045301, 16
-
1
tz.transition 1969, 10, :o1, 117144637, 48
-
1
tz.transition 1970, 4, :o2, 9315000
-
1
tz.transition 1970, 10, :o1, 25036200
-
1
tz.transition 1971, 4, :o2, 40764600
-
1
tz.transition 1971, 10, :o1, 56485800
-
1
tz.transition 1972, 4, :o2, 72214200
-
1
tz.transition 1972, 10, :o1, 88540200
-
1
tz.transition 1973, 4, :o2, 104268600
-
1
tz.transition 1973, 10, :o1, 119989800
-
1
tz.transition 1973, 12, :o2, 126041400
-
1
tz.transition 1974, 10, :o1, 151439400
-
1
tz.transition 1975, 4, :o2, 167167800
-
1
tz.transition 1975, 10, :o1, 182889000
-
1
tz.transition 1976, 4, :o2, 198617400
-
1
tz.transition 1976, 10, :o1, 214338600
-
1
tz.transition 1979, 5, :o2, 295385400
-
1
tz.transition 1979, 10, :o1, 309292200
-
end
-
end
-
end
-
end
-
end
-
1
module TZInfo
-
1
module Definitions
-
1
module Asia
-
1
module Irkutsk
-
1
include TimezoneDefinition
-
-
1
timezone 'Asia/Irkutsk' do |tz|
-
1
tz.offset :o0, 25040, 0, :LMT
-
1
tz.offset :o1, 25040, 0, :IMT
-
1
tz.offset :o2, 25200, 0, :IRKT
-
1
tz.offset :o3, 28800, 0, :IRKT
-
1
tz.offset :o4, 28800, 3600, :IRKST
-
1
tz.offset :o5, 25200, 3600, :IRKST
-
1
tz.offset :o6, 32400, 0, :IRKT
-
-
1
tz.transition 1879, 12, :o1, 2600332427, 1080
-
1
tz.transition 1920, 1, :o2, 2616136067, 1080
-
1
tz.transition 1930, 6, :o3, 58227557, 24
-
1
tz.transition 1981, 3, :o4, 354902400
-
1
tz.transition 1981, 9, :o3, 370710000
-
1
tz.transition 1982, 3, :o4, 386438400
-
1
tz.transition 1982, 9, :o3, 402246000
-
1
tz.transition 1983, 3, :o4, 417974400
-
1
tz.transition 1983, 9, :o3, 433782000
-
1
tz.transition 1984, 3, :o4, 449596800
-
1
tz.transition 1984, 9, :o3, 465328800
-
1
tz.transition 1985, 3, :o4, 481053600
-
1
tz.transition 1985, 9, :o3, 496778400
-
1
tz.transition 1986, 3, :o4, 512503200
-
1
tz.transition 1986, 9, :o3, 528228000
-
1
tz.transition 1987, 3, :o4, 543952800
-
1
tz.transition 1987, 9, :o3, 559677600
-
1
tz.transition 1988, 3, :o4, 575402400
-
1
tz.transition 1988, 9, :o3, 591127200
-
1
tz.transition 1989, 3, :o4, 606852000
-
1
tz.transition 1989, 9, :o3, 622576800
-
1
tz.transition 1990, 3, :o4, 638301600
-
1
tz.transition 1990, 9, :o3, 654631200
-
1
tz.transition 1991, 3, :o5, 670356000
-
1
tz.transition 1991, 9, :o2, 686084400
-
1
tz.transition 1992, 1, :o3, 695761200
-
1
tz.transition 1992, 3, :o4, 701794800
-
1
tz.transition 1992, 9, :o3, 717516000
-
1
tz.transition 1993, 3, :o4, 733255200
-
1
tz.transition 1993, 9, :o3, 748980000
-
1
tz.transition 1994, 3, :o4, 764704800
-
1
tz.transition 1994, 9, :o3, 780429600
-
1
tz.transition 1995, 3, :o4, 796154400
-
1
tz.transition 1995, 9, :o3, 811879200
-
1
tz.transition 1996, 3, :o4, 828208800
-
1
tz.transition 1996, 10, :o3, 846352800
-
1
tz.transition 1997, 3, :o4, 859658400
-
1
tz.transition 1997, 10, :o3, 877802400
-
1
tz.transition 1998, 3, :o4, 891108000
-
1
tz.transition 1998, 10, :o3, 909252000
-
1
tz.transition 1999, 3, :o4, 922557600
-
1
tz.transition 1999, 10, :o3, 941306400
-
1
tz.transition 2000, 3, :o4, 954007200
-
1
tz.transition 2000, 10, :o3, 972756000
-
1
tz.transition 2001, 3, :o4, 985456800
-
1
tz.transition 2001, 10, :o3, 1004205600
-
1
tz.transition 2002, 3, :o4, 1017511200
-
1
tz.transition 2002, 10, :o3, 1035655200
-
1
tz.transition 2003, 3, :o4, 1048960800
-
1
tz.transition 2003, 10, :o3, 1067104800
-
1
tz.transition 2004, 3, :o4, 1080410400
-
1
tz.transition 2004, 10, :o3, 1099159200
-
1
tz.transition 2005, 3, :o4, 1111860000
-
1
tz.transition 2005, 10, :o3, 1130608800
-
1
tz.transition 2006, 3, :o4, 1143309600
-
1
tz.transition 2006, 10, :o3, 1162058400
-
1
tz.transition 2007, 3, :o4, 1174759200
-
1
tz.transition 2007, 10, :o3, 1193508000
-
1
tz.transition 2008, 3, :o4, 1206813600
-
1
tz.transition 2008, 10, :o3, 1224957600
-
1
tz.transition 2009, 3, :o4, 1238263200
-
1
tz.transition 2009, 10, :o3, 1256407200
-
1
tz.transition 2010, 3, :o4, 1269712800
-
1
tz.transition 2010, 10, :o3, 1288461600
-
1
tz.transition 2011, 3, :o6, 1301162400
-
end
-
end
-
end
-
end
-
end
-
1
module TZInfo
-
1
module Definitions
-
1
module Asia
-
1
module Jakarta
-
1
include TimezoneDefinition
-
-
1
timezone 'Asia/Jakarta' do |tz|
-
1
tz.offset :o0, 25632, 0, :LMT
-
1
tz.offset :o1, 25632, 0, :JMT
-
1
tz.offset :o2, 26400, 0, :JAVT
-
1
tz.offset :o3, 27000, 0, :WIT
-
1
tz.offset :o4, 32400, 0, :JST
-
1
tz.offset :o5, 28800, 0, :WIT
-
1
tz.offset :o6, 25200, 0, :WIT
-
-
1
tz.transition 1867, 8, :o1, 720956461, 300
-
1
tz.transition 1923, 12, :o2, 87256267, 36
-
1
tz.transition 1932, 10, :o3, 87372439, 36
-
1
tz.transition 1942, 3, :o4, 38887059, 16
-
1
tz.transition 1945, 9, :o3, 19453769, 8
-
1
tz.transition 1948, 4, :o5, 38922755, 16
-
1
tz.transition 1950, 4, :o3, 14600413, 6
-
1
tz.transition 1963, 12, :o6, 39014323, 16
-
end
-
end
-
end
-
end
-
end
-
1
module TZInfo
-
1
module Definitions
-
1
module Asia
-
1
module Jerusalem
-
1
include TimezoneDefinition
-
-
1
timezone 'Asia/Jerusalem' do |tz|
-
1
tz.offset :o0, 8456, 0, :LMT
-
1
tz.offset :o1, 8440, 0, :JMT
-
1
tz.offset :o2, 7200, 0, :IST
-
1
tz.offset :o3, 7200, 3600, :IDT
-
1
tz.offset :o4, 7200, 7200, :IDDT
-
-
1
tz.transition 1879, 12, :o1, 26003326343, 10800
-
1
tz.transition 1917, 12, :o2, 5230643909, 2160
-
1
tz.transition 1940, 5, :o3, 29157377, 12
-
1
tz.transition 1942, 10, :o2, 19445315, 8
-
1
tz.transition 1943, 4, :o3, 4861631, 2
-
1
tz.transition 1943, 10, :o2, 19448235, 8
-
1
tz.transition 1944, 3, :o3, 29174177, 12
-
1
tz.transition 1944, 10, :o2, 19451163, 8
-
1
tz.transition 1945, 4, :o3, 29178737, 12
-
1
tz.transition 1945, 10, :o2, 58362251, 24
-
1
tz.transition 1946, 4, :o3, 4863853, 2
-
1
tz.transition 1946, 10, :o2, 19457003, 8
-
1
tz.transition 1948, 5, :o4, 29192333, 12
-
1
tz.transition 1948, 8, :o3, 7298386, 3
-
1
tz.transition 1948, 10, :o2, 58388555, 24
-
1
tz.transition 1949, 4, :o3, 29196449, 12
-
1
tz.transition 1949, 10, :o2, 58397315, 24
-
1
tz.transition 1950, 4, :o3, 29200649, 12
-
1
tz.transition 1950, 9, :o2, 4867079, 2
-
1
tz.transition 1951, 3, :o3, 29204849, 12
-
1
tz.transition 1951, 11, :o2, 4867923, 2
-
1
tz.transition 1952, 4, :o3, 4868245, 2
-
1
tz.transition 1952, 10, :o2, 4868609, 2
-
1
tz.transition 1953, 4, :o3, 4868959, 2
-
1
tz.transition 1953, 9, :o2, 4869267, 2
-
1
tz.transition 1954, 6, :o3, 29218877, 12
-
1
tz.transition 1954, 9, :o2, 19479979, 8
-
1
tz.transition 1955, 6, :o3, 4870539, 2
-
1
tz.transition 1955, 9, :o2, 19482891, 8
-
1
tz.transition 1956, 6, :o3, 29227529, 12
-
1
tz.transition 1956, 9, :o2, 4871493, 2
-
1
tz.transition 1957, 4, :o3, 4871915, 2
-
1
tz.transition 1957, 9, :o2, 19488827, 8
-
1
tz.transition 1974, 7, :o3, 142380000
-
1
tz.transition 1974, 10, :o2, 150843600
-
1
tz.transition 1975, 4, :o3, 167176800
-
1
tz.transition 1975, 8, :o2, 178664400
-
1
tz.transition 1985, 4, :o3, 482277600
-
1
tz.transition 1985, 9, :o2, 495579600
-
1
tz.transition 1986, 5, :o3, 516751200
-
1
tz.transition 1986, 9, :o2, 526424400
-
1
tz.transition 1987, 4, :o3, 545436000
-
1
tz.transition 1987, 9, :o2, 558478800
-
1
tz.transition 1988, 4, :o3, 576540000
-
1
tz.transition 1988, 9, :o2, 589237200
-
1
tz.transition 1989, 4, :o3, 609890400
-
1
tz.transition 1989, 9, :o2, 620773200
-
1
tz.transition 1990, 3, :o3, 638316000
-
1
tz.transition 1990, 8, :o2, 651618000
-
1
tz.transition 1991, 3, :o3, 669765600
-
1
tz.transition 1991, 8, :o2, 683672400
-
1
tz.transition 1992, 3, :o3, 701820000
-
1
tz.transition 1992, 9, :o2, 715726800
-
1
tz.transition 1993, 4, :o3, 733701600
-
1
tz.transition 1993, 9, :o2, 747176400
-
1
tz.transition 1994, 3, :o3, 765151200
-
1
tz.transition 1994, 8, :o2, 778021200
-
1
tz.transition 1995, 3, :o3, 796600800
-
1
tz.transition 1995, 9, :o2, 810075600
-
1
tz.transition 1996, 3, :o3, 826840800
-
1
tz.transition 1996, 9, :o2, 842821200
-
1
tz.transition 1997, 3, :o3, 858895200
-
1
tz.transition 1997, 9, :o2, 874184400
-
1
tz.transition 1998, 3, :o3, 890344800
-
1
tz.transition 1998, 9, :o2, 905029200
-
1
tz.transition 1999, 4, :o3, 923011200
-
1
tz.transition 1999, 9, :o2, 936313200
-
1
tz.transition 2000, 4, :o3, 955670400
-
1
tz.transition 2000, 10, :o2, 970783200
-
1
tz.transition 2001, 4, :o3, 986770800
-
1
tz.transition 2001, 9, :o2, 1001282400
-
1
tz.transition 2002, 3, :o3, 1017356400
-
1
tz.transition 2002, 10, :o2, 1033941600
-
1
tz.transition 2003, 3, :o3, 1048806000
-
1
tz.transition 2003, 10, :o2, 1065132000
-
1
tz.transition 2004, 4, :o3, 1081292400
-
1
tz.transition 2004, 9, :o2, 1095804000
-
1
tz.transition 2005, 4, :o3, 1112313600
-
1
tz.transition 2005, 10, :o2, 1128812400
-
1
tz.transition 2006, 3, :o3, 1143763200
-
1
tz.transition 2006, 9, :o2, 1159657200
-
1
tz.transition 2007, 3, :o3, 1175212800
-
1
tz.transition 2007, 9, :o2, 1189897200
-
1
tz.transition 2008, 3, :o3, 1206662400
-
1
tz.transition 2008, 10, :o2, 1223161200
-
1
tz.transition 2009, 3, :o3, 1238112000
-
1
tz.transition 2009, 9, :o2, 1254006000
-
1
tz.transition 2010, 3, :o3, 1269561600
-
1
tz.transition 2010, 9, :o2, 1284246000
-
1
tz.transition 2011, 4, :o3, 1301616000
-
1
tz.transition 2011, 10, :o2, 1317510000
-
1
tz.transition 2012, 3, :o3, 1333065600
-
1
tz.transition 2012, 9, :o2, 1348354800
-
1
tz.transition 2013, 3, :o3, 1364515200
-
1
tz.transition 2013, 10, :o2, 1381014000
-
1
tz.transition 2014, 3, :o3, 1395964800
-
1
tz.transition 2014, 10, :o2, 1412463600
-
1
tz.transition 2015, 3, :o3, 1427414400
-
1
tz.transition 2015, 10, :o2, 1443913200
-
1
tz.transition 2016, 3, :o3, 1458864000
-
1
tz.transition 2016, 10, :o2, 1475362800
-
1
tz.transition 2017, 3, :o3, 1490313600
-
1
tz.transition 2017, 10, :o2, 1507417200
-
1
tz.transition 2018, 3, :o3, 1521763200
-
1
tz.transition 2018, 10, :o2, 1538866800
-
1
tz.transition 2019, 3, :o3, 1553817600
-
1
tz.transition 2019, 10, :o2, 1570316400
-
1
tz.transition 2020, 3, :o3, 1585267200
-
1
tz.transition 2020, 10, :o2, 1601766000
-
1
tz.transition 2021, 3, :o3, 1616716800
-
1
tz.transition 2021, 10, :o2, 1633215600
-
1
tz.transition 2022, 3, :o3, 1648166400
-
1
tz.transition 2022, 10, :o2, 1664665200
-
1
tz.transition 2023, 3, :o3, 1679616000
-
1
tz.transition 2023, 10, :o2, 1696719600
-
1
tz.transition 2024, 3, :o3, 1711670400
-
1
tz.transition 2024, 10, :o2, 1728169200
-
1
tz.transition 2025, 3, :o3, 1743120000
-
1
tz.transition 2025, 10, :o2, 1759618800
-
1
tz.transition 2026, 3, :o3, 1774569600
-
1
tz.transition 2026, 10, :o2, 1791068400
-
1
tz.transition 2027, 3, :o3, 1806019200
-
1
tz.transition 2027, 10, :o2, 1822604400
-
1
tz.transition 2028, 3, :o3, 1837468800
-
1
tz.transition 2028, 10, :o2, 1854572400
-
1
tz.transition 2029, 3, :o3, 1868918400
-
1
tz.transition 2029, 10, :o2, 1886022000
-
1
tz.transition 2030, 3, :o3, 1900972800
-
1
tz.transition 2030, 10, :o2, 1917471600
-
1
tz.transition 2031, 3, :o3, 1932422400
-
1
tz.transition 2031, 10, :o2, 1948921200
-
1
tz.transition 2032, 3, :o3, 1963872000
-
1
tz.transition 2032, 10, :o2, 1980370800
-
1
tz.transition 2033, 3, :o3, 1995321600
-
1
tz.transition 2033, 10, :o2, 2011820400
-
1
tz.transition 2034, 3, :o3, 2026771200
-
1
tz.transition 2034, 10, :o2, 2043874800
-
1
tz.transition 2035, 3, :o3, 2058220800
-
1
tz.transition 2035, 10, :o2, 2075324400
-
1
tz.transition 2036, 3, :o3, 2090275200
-
1
tz.transition 2036, 10, :o2, 2106774000
-
1
tz.transition 2037, 3, :o3, 2121724800
-
1
tz.transition 2037, 10, :o2, 2138223600
-
1
tz.transition 2038, 3, :o3, 4931017, 2
-
1
tz.transition 2038, 10, :o2, 59176787, 24
-
1
tz.transition 2039, 3, :o3, 4931745, 2
-
1
tz.transition 2039, 10, :o2, 59185523, 24
-
1
tz.transition 2040, 3, :o3, 4932473, 2
-
1
tz.transition 2040, 10, :o2, 59194427, 24
-
1
tz.transition 2041, 3, :o3, 4933215, 2
-
1
tz.transition 2041, 10, :o2, 59203163, 24
-
1
tz.transition 2042, 3, :o3, 4933943, 2
-
1
tz.transition 2042, 10, :o2, 59211899, 24
-
1
tz.transition 2043, 3, :o3, 4934671, 2
-
1
tz.transition 2043, 10, :o2, 59220635, 24
-
1
tz.transition 2044, 3, :o3, 4935399, 2
-
1
tz.transition 2044, 10, :o2, 59229371, 24
-
1
tz.transition 2045, 3, :o3, 4936127, 2
-
1
tz.transition 2045, 10, :o2, 59238275, 24
-
1
tz.transition 2046, 3, :o3, 4936855, 2
-
1
tz.transition 2046, 10, :o2, 59247011, 24
-
1
tz.transition 2047, 3, :o3, 4937597, 2
-
1
tz.transition 2047, 10, :o2, 59255747, 24
-
1
tz.transition 2048, 3, :o3, 4938325, 2
-
1
tz.transition 2048, 10, :o2, 59264483, 24
-
1
tz.transition 2049, 3, :o3, 4939053, 2
-
1
tz.transition 2049, 10, :o2, 59273219, 24
-
1
tz.transition 2050, 3, :o3, 4939781, 2
-
1
tz.transition 2050, 10, :o2, 59281955, 24
-
end
-
end
-
end
-
end
-
end
-
1
module TZInfo
-
1
module Definitions
-
1
module Asia
-
1
module Kabul
-
1
include TimezoneDefinition
-
-
1
timezone 'Asia/Kabul' do |tz|
-
1
tz.offset :o0, 16608, 0, :LMT
-
1
tz.offset :o1, 14400, 0, :AFT
-
1
tz.offset :o2, 16200, 0, :AFT
-
-
1
tz.transition 1889, 12, :o1, 2170231477, 900
-
1
tz.transition 1944, 12, :o2, 7294369, 3
-
end
-
end
-
end
-
end
-
end
-
1
module TZInfo
-
1
module Definitions
-
1
module Asia
-
1
module Kamchatka
-
1
include TimezoneDefinition
-
-
1
timezone 'Asia/Kamchatka' do |tz|
-
1
tz.offset :o0, 38076, 0, :LMT
-
1
tz.offset :o1, 39600, 0, :PETT
-
1
tz.offset :o2, 43200, 0, :PETT
-
1
tz.offset :o3, 43200, 3600, :PETST
-
1
tz.offset :o4, 39600, 3600, :PETST
-
-
1
tz.transition 1922, 11, :o1, 17448250027, 7200
-
1
tz.transition 1930, 6, :o2, 58227553, 24
-
1
tz.transition 1981, 3, :o3, 354888000
-
1
tz.transition 1981, 9, :o2, 370695600
-
1
tz.transition 1982, 3, :o3, 386424000
-
1
tz.transition 1982, 9, :o2, 402231600
-
1
tz.transition 1983, 3, :o3, 417960000
-
1
tz.transition 1983, 9, :o2, 433767600
-
1
tz.transition 1984, 3, :o3, 449582400
-
1
tz.transition 1984, 9, :o2, 465314400
-
1
tz.transition 1985, 3, :o3, 481039200
-
1
tz.transition 1985, 9, :o2, 496764000
-
1
tz.transition 1986, 3, :o3, 512488800
-
1
tz.transition 1986, 9, :o2, 528213600
-
1
tz.transition 1987, 3, :o3, 543938400
-
1
tz.transition 1987, 9, :o2, 559663200
-
1
tz.transition 1988, 3, :o3, 575388000
-
1
tz.transition 1988, 9, :o2, 591112800
-
1
tz.transition 1989, 3, :o3, 606837600
-
1
tz.transition 1989, 9, :o2, 622562400
-
1
tz.transition 1990, 3, :o3, 638287200
-
1
tz.transition 1990, 9, :o2, 654616800
-
1
tz.transition 1991, 3, :o4, 670341600
-
1
tz.transition 1991, 9, :o1, 686070000
-
1
tz.transition 1992, 1, :o2, 695746800
-
1
tz.transition 1992, 3, :o3, 701780400
-
1
tz.transition 1992, 9, :o2, 717501600
-
1
tz.transition 1993, 3, :o3, 733240800
-
1
tz.transition 1993, 9, :o2, 748965600
-
1
tz.transition 1994, 3, :o3, 764690400
-
1
tz.transition 1994, 9, :o2, 780415200
-
1
tz.transition 1995, 3, :o3, 796140000
-
1
tz.transition 1995, 9, :o2, 811864800
-
1
tz.transition 1996, 3, :o3, 828194400
-
1
tz.transition 1996, 10, :o2, 846338400
-
1
tz.transition 1997, 3, :o3, 859644000
-
1
tz.transition 1997, 10, :o2, 877788000
-
1
tz.transition 1998, 3, :o3, 891093600
-
1
tz.transition 1998, 10, :o2, 909237600
-
1
tz.transition 1999, 3, :o3, 922543200
-
1
tz.transition 1999, 10, :o2, 941292000
-
1
tz.transition 2000, 3, :o3, 953992800
-
1
tz.transition 2000, 10, :o2, 972741600
-
1
tz.transition 2001, 3, :o3, 985442400
-
1
tz.transition 2001, 10, :o2, 1004191200
-
1
tz.transition 2002, 3, :o3, 1017496800
-
1
tz.transition 2002, 10, :o2, 1035640800
-
1
tz.transition 2003, 3, :o3, 1048946400
-
1
tz.transition 2003, 10, :o2, 1067090400
-
1
tz.transition 2004, 3, :o3, 1080396000
-
1
tz.transition 2004, 10, :o2, 1099144800
-
1
tz.transition 2005, 3, :o3, 1111845600
-
1
tz.transition 2005, 10, :o2, 1130594400
-
1
tz.transition 2006, 3, :o3, 1143295200
-
1
tz.transition 2006, 10, :o2, 1162044000
-
1
tz.transition 2007, 3, :o3, 1174744800
-
1
tz.transition 2007, 10, :o2, 1193493600
-
1
tz.transition 2008, 3, :o3, 1206799200
-
1
tz.transition 2008, 10, :o2, 1224943200
-
1
tz.transition 2009, 3, :o3, 1238248800
-
1
tz.transition 2009, 10, :o2, 1256392800
-
1
tz.transition 2010, 3, :o4, 1269698400
-
1
tz.transition 2010, 10, :o1, 1288450800
-
1
tz.transition 2011, 3, :o2, 1301151600
-
end
-
end
-
end
-
end
-
end
-
1
module TZInfo
-
1
module Definitions
-
1
module Asia
-
1
module Karachi
-
1
include TimezoneDefinition
-
-
1
timezone 'Asia/Karachi' do |tz|
-
1
tz.offset :o0, 16092, 0, :LMT
-
1
tz.offset :o1, 19800, 0, :IST
-
1
tz.offset :o2, 19800, 3600, :IST
-
1
tz.offset :o3, 18000, 0, :KART
-
1
tz.offset :o4, 18000, 0, :PKT
-
1
tz.offset :o5, 18000, 3600, :PKST
-
-
1
tz.transition 1906, 12, :o1, 1934061051, 800
-
1
tz.transition 1942, 8, :o2, 116668957, 48
-
1
tz.transition 1945, 10, :o1, 116723675, 48
-
1
tz.transition 1951, 9, :o3, 116828125, 48
-
1
tz.transition 1971, 3, :o4, 38775600
-
1
tz.transition 2002, 4, :o5, 1018119660
-
1
tz.transition 2002, 10, :o4, 1033840860
-
1
tz.transition 2008, 5, :o5, 1212260400
-
1
tz.transition 2008, 10, :o4, 1225476000
-
1
tz.transition 2009, 4, :o5, 1239735600
-
1
tz.transition 2009, 10, :o4, 1257012000
-
end
-
end
-
end
-
end
-
end
-
1
module TZInfo
-
1
module Definitions
-
1
module Asia
-
1
module Kathmandu
-
1
include TimezoneDefinition
-
-
1
timezone 'Asia/Kathmandu' do |tz|
-
1
tz.offset :o0, 20476, 0, :LMT
-
1
tz.offset :o1, 19800, 0, :IST
-
1
tz.offset :o2, 20700, 0, :NPT
-
-
1
tz.transition 1919, 12, :o1, 52322204081, 21600
-
1
tz.transition 1985, 12, :o2, 504901800
-
end
-
end
-
end
-
end
-
end
-
1
module TZInfo
-
1
module Definitions
-
1
module Asia
-
1
module Kolkata
-
1
include TimezoneDefinition
-
-
1
timezone 'Asia/Kolkata' do |tz|
-
1
tz.offset :o0, 21208, 0, :LMT
-
1
tz.offset :o1, 21200, 0, :HMT
-
1
tz.offset :o2, 23400, 0, :BURT
-
1
tz.offset :o3, 19800, 0, :IST
-
1
tz.offset :o4, 19800, 3600, :IST
-
-
1
tz.transition 1879, 12, :o1, 26003324749, 10800
-
1
tz.transition 1941, 9, :o2, 524937943, 216
-
1
tz.transition 1942, 5, :o3, 116663723, 48
-
1
tz.transition 1942, 8, :o4, 116668957, 48
-
1
tz.transition 1945, 10, :o3, 116723675, 48
-
end
-
end
-
end
-
end
-
end
-
1
module TZInfo
-
1
module Definitions
-
1
module Asia
-
1
module Krasnoyarsk
-
1
include TimezoneDefinition
-
-
1
timezone 'Asia/Krasnoyarsk' do |tz|
-
1
tz.offset :o0, 22280, 0, :LMT
-
1
tz.offset :o1, 21600, 0, :KRAT
-
1
tz.offset :o2, 25200, 0, :KRAT
-
1
tz.offset :o3, 25200, 3600, :KRAST
-
1
tz.offset :o4, 21600, 3600, :KRAST
-
1
tz.offset :o5, 28800, 0, :KRAT
-
-
1
tz.transition 1920, 1, :o1, 5232231163, 2160
-
1
tz.transition 1930, 6, :o2, 9704593, 4
-
1
tz.transition 1981, 3, :o3, 354906000
-
1
tz.transition 1981, 9, :o2, 370713600
-
1
tz.transition 1982, 3, :o3, 386442000
-
1
tz.transition 1982, 9, :o2, 402249600
-
1
tz.transition 1983, 3, :o3, 417978000
-
1
tz.transition 1983, 9, :o2, 433785600
-
1
tz.transition 1984, 3, :o3, 449600400
-
1
tz.transition 1984, 9, :o2, 465332400
-
1
tz.transition 1985, 3, :o3, 481057200
-
1
tz.transition 1985, 9, :o2, 496782000
-
1
tz.transition 1986, 3, :o3, 512506800
-
1
tz.transition 1986, 9, :o2, 528231600
-
1
tz.transition 1987, 3, :o3, 543956400
-
1
tz.transition 1987, 9, :o2, 559681200
-
1
tz.transition 1988, 3, :o3, 575406000
-
1
tz.transition 1988, 9, :o2, 591130800
-
1
tz.transition 1989, 3, :o3, 606855600
-
1
tz.transition 1989, 9, :o2, 622580400
-
1
tz.transition 1990, 3, :o3, 638305200
-
1
tz.transition 1990, 9, :o2, 654634800
-
1
tz.transition 1991, 3, :o4, 670359600
-
1
tz.transition 1991, 9, :o1, 686088000
-
1
tz.transition 1992, 1, :o2, 695764800
-
1
tz.transition 1992, 3, :o3, 701798400
-
1
tz.transition 1992, 9, :o2, 717519600
-
1
tz.transition 1993, 3, :o3, 733258800
-
1
tz.transition 1993, 9, :o2, 748983600
-
1
tz.transition 1994, 3, :o3, 764708400
-
1
tz.transition 1994, 9, :o2, 780433200
-
1
tz.transition 1995, 3, :o3, 796158000
-
1
tz.transition 1995, 9, :o2, 811882800
-
1
tz.transition 1996, 3, :o3, 828212400
-
1
tz.transition 1996, 10, :o2, 846356400
-
1
tz.transition 1997, 3, :o3, 859662000
-
1
tz.transition 1997, 10, :o2, 877806000
-
1
tz.transition 1998, 3, :o3, 891111600
-
1
tz.transition 1998, 10, :o2, 909255600
-
1
tz.transition 1999, 3, :o3, 922561200
-
1
tz.transition 1999, 10, :o2, 941310000
-
1
tz.transition 2000, 3, :o3, 954010800
-
1
tz.transition 2000, 10, :o2, 972759600
-
1
tz.transition 2001, 3, :o3, 985460400
-
1
tz.transition 2001, 10, :o2, 1004209200
-
1
tz.transition 2002, 3, :o3, 1017514800
-
1
tz.transition 2002, 10, :o2, 1035658800
-
1
tz.transition 2003, 3, :o3, 1048964400
-
1
tz.transition 2003, 10, :o2, 1067108400
-
1
tz.transition 2004, 3, :o3, 1080414000
-
1
tz.transition 2004, 10, :o2, 1099162800
-
1
tz.transition 2005, 3, :o3, 1111863600
-
1
tz.transition 2005, 10, :o2, 1130612400
-
1
tz.transition 2006, 3, :o3, 1143313200
-
1
tz.transition 2006, 10, :o2, 1162062000
-
1
tz.transition 2007, 3, :o3, 1174762800
-
1
tz.transition 2007, 10, :o2, 1193511600
-
1
tz.transition 2008, 3, :o3, 1206817200
-
1
tz.transition 2008, 10, :o2, 1224961200
-
1
tz.transition 2009, 3, :o3, 1238266800
-
1
tz.transition 2009, 10, :o2, 1256410800
-
1
tz.transition 2010, 3, :o3, 1269716400
-
1
tz.transition 2010, 10, :o2, 1288465200
-
1
tz.transition 2011, 3, :o5, 1301166000
-
end
-
end
-
end
-
end
-
end
-
1
module TZInfo
-
1
module Definitions
-
1
module Asia
-
1
module Kuala_Lumpur
-
1
include TimezoneDefinition
-
-
1
timezone 'Asia/Kuala_Lumpur' do |tz|
-
1
tz.offset :o0, 24406, 0, :LMT
-
1
tz.offset :o1, 24925, 0, :SMT
-
1
tz.offset :o2, 25200, 0, :MALT
-
1
tz.offset :o3, 25200, 1200, :MALST
-
1
tz.offset :o4, 26400, 0, :MALT
-
1
tz.offset :o5, 27000, 0, :MALT
-
1
tz.offset :o6, 32400, 0, :JST
-
1
tz.offset :o7, 28800, 0, :MYT
-
-
1
tz.transition 1900, 12, :o1, 104344641397, 43200
-
1
tz.transition 1905, 5, :o2, 8353142363, 3456
-
1
tz.transition 1932, 12, :o3, 58249757, 24
-
1
tz.transition 1935, 12, :o4, 87414055, 36
-
1
tz.transition 1941, 8, :o5, 87488575, 36
-
1
tz.transition 1942, 2, :o6, 38886499, 16
-
1
tz.transition 1945, 9, :o5, 19453681, 8
-
1
tz.transition 1981, 12, :o7, 378664200
-
end
-
end
-
end
-
end
-
end
-
1
module TZInfo
-
1
module Definitions
-
1
module Asia
-
1
module Kuwait
-
1
include TimezoneDefinition
-
-
1
timezone 'Asia/Kuwait' do |tz|
-
1
tz.offset :o0, 11516, 0, :LMT
-
1
tz.offset :o1, 10800, 0, :AST
-
-
1
tz.transition 1949, 12, :o1, 52558899121, 21600
-
end
-
end
-
end
-
end
-
end
-
1
module TZInfo
-
1
module Definitions
-
1
module Asia
-
1
module Magadan
-
1
include TimezoneDefinition
-
-
1
timezone 'Asia/Magadan' do |tz|
-
1
tz.offset :o0, 36192, 0, :LMT
-
1
tz.offset :o1, 36000, 0, :MAGT
-
1
tz.offset :o2, 39600, 0, :MAGT
-
1
tz.offset :o3, 39600, 3600, :MAGST
-
1
tz.offset :o4, 36000, 3600, :MAGST
-
1
tz.offset :o5, 43200, 0, :MAGT
-
-
1
tz.transition 1924, 5, :o1, 2181516373, 900
-
1
tz.transition 1930, 6, :o2, 29113777, 12
-
1
tz.transition 1981, 3, :o3, 354891600
-
1
tz.transition 1981, 9, :o2, 370699200
-
1
tz.transition 1982, 3, :o3, 386427600
-
1
tz.transition 1982, 9, :o2, 402235200
-
1
tz.transition 1983, 3, :o3, 417963600
-
1
tz.transition 1983, 9, :o2, 433771200
-
1
tz.transition 1984, 3, :o3, 449586000
-
1
tz.transition 1984, 9, :o2, 465318000
-
1
tz.transition 1985, 3, :o3, 481042800
-
1
tz.transition 1985, 9, :o2, 496767600
-
1
tz.transition 1986, 3, :o3, 512492400
-
1
tz.transition 1986, 9, :o2, 528217200
-
1
tz.transition 1987, 3, :o3, 543942000
-
1
tz.transition 1987, 9, :o2, 559666800
-
1
tz.transition 1988, 3, :o3, 575391600
-
1
tz.transition 1988, 9, :o2, 591116400
-
1
tz.transition 1989, 3, :o3, 606841200
-
1
tz.transition 1989, 9, :o2, 622566000
-
1
tz.transition 1990, 3, :o3, 638290800
-
1
tz.transition 1990, 9, :o2, 654620400
-
1
tz.transition 1991, 3, :o4, 670345200
-
1
tz.transition 1991, 9, :o1, 686073600
-
1
tz.transition 1992, 1, :o2, 695750400
-
1
tz.transition 1992, 3, :o3, 701784000
-
1
tz.transition 1992, 9, :o2, 717505200
-
1
tz.transition 1993, 3, :o3, 733244400
-
1
tz.transition 1993, 9, :o2, 748969200
-
1
tz.transition 1994, 3, :o3, 764694000
-
1
tz.transition 1994, 9, :o2, 780418800
-
1
tz.transition 1995, 3, :o3, 796143600
-
1
tz.transition 1995, 9, :o2, 811868400
-
1
tz.transition 1996, 3, :o3, 828198000
-
1
tz.transition 1996, 10, :o2, 846342000
-
1
tz.transition 1997, 3, :o3, 859647600
-
1
tz.transition 1997, 10, :o2, 877791600
-
1
tz.transition 1998, 3, :o3, 891097200
-
1
tz.transition 1998, 10, :o2, 909241200
-
1
tz.transition 1999, 3, :o3, 922546800
-
1
tz.transition 1999, 10, :o2, 941295600
-
1
tz.transition 2000, 3, :o3, 953996400
-
1
tz.transition 2000, 10, :o2, 972745200
-
1
tz.transition 2001, 3, :o3, 985446000
-
1
tz.transition 2001, 10, :o2, 1004194800
-
1
tz.transition 2002, 3, :o3, 1017500400
-
1
tz.transition 2002, 10, :o2, 1035644400
-
1
tz.transition 2003, 3, :o3, 1048950000
-
1
tz.transition 2003, 10, :o2, 1067094000
-
1
tz.transition 2004, 3, :o3, 1080399600
-
1
tz.transition 2004, 10, :o2, 1099148400
-
1
tz.transition 2005, 3, :o3, 1111849200
-
1
tz.transition 2005, 10, :o2, 1130598000
-
1
tz.transition 2006, 3, :o3, 1143298800
-
1
tz.transition 2006, 10, :o2, 1162047600
-
1
tz.transition 2007, 3, :o3, 1174748400
-
1
tz.transition 2007, 10, :o2, 1193497200
-
1
tz.transition 2008, 3, :o3, 1206802800
-
1
tz.transition 2008, 10, :o2, 1224946800
-
1
tz.transition 2009, 3, :o3, 1238252400
-
1
tz.transition 2009, 10, :o2, 1256396400
-
1
tz.transition 2010, 3, :o3, 1269702000
-
1
tz.transition 2010, 10, :o2, 1288450800
-
1
tz.transition 2011, 3, :o5, 1301151600
-
end
-
end
-
end
-
end
-
end
-
1
module TZInfo
-
1
module Definitions
-
1
module Asia
-
1
module Muscat
-
1
include TimezoneDefinition
-
-
1
timezone 'Asia/Muscat' do |tz|
-
1
tz.offset :o0, 14060, 0, :LMT
-
1
tz.offset :o1, 14400, 0, :GST
-
-
1
tz.transition 1919, 12, :o1, 10464441137, 4320
-
end
-
end
-
end
-
end
-
end
-
1
module TZInfo
-
1
module Definitions
-
1
module Asia
-
1
module Novosibirsk
-
1
include TimezoneDefinition
-
-
1
timezone 'Asia/Novosibirsk' do |tz|
-
1
tz.offset :o0, 19900, 0, :LMT
-
1
tz.offset :o1, 21600, 0, :NOVT
-
1
tz.offset :o2, 25200, 0, :NOVT
-
1
tz.offset :o3, 25200, 3600, :NOVST
-
1
tz.offset :o4, 21600, 3600, :NOVST
-
-
1
tz.transition 1919, 12, :o1, 2092872833, 864
-
1
tz.transition 1930, 6, :o2, 9704593, 4
-
1
tz.transition 1981, 3, :o3, 354906000
-
1
tz.transition 1981, 9, :o2, 370713600
-
1
tz.transition 1982, 3, :o3, 386442000
-
1
tz.transition 1982, 9, :o2, 402249600
-
1
tz.transition 1983, 3, :o3, 417978000
-
1
tz.transition 1983, 9, :o2, 433785600
-
1
tz.transition 1984, 3, :o3, 449600400
-
1
tz.transition 1984, 9, :o2, 465332400
-
1
tz.transition 1985, 3, :o3, 481057200
-
1
tz.transition 1985, 9, :o2, 496782000
-
1
tz.transition 1986, 3, :o3, 512506800
-
1
tz.transition 1986, 9, :o2, 528231600
-
1
tz.transition 1987, 3, :o3, 543956400
-
1
tz.transition 1987, 9, :o2, 559681200
-
1
tz.transition 1988, 3, :o3, 575406000
-
1
tz.transition 1988, 9, :o2, 591130800
-
1
tz.transition 1989, 3, :o3, 606855600
-
1
tz.transition 1989, 9, :o2, 622580400
-
1
tz.transition 1990, 3, :o3, 638305200
-
1
tz.transition 1990, 9, :o2, 654634800
-
1
tz.transition 1991, 3, :o4, 670359600
-
1
tz.transition 1991, 9, :o1, 686088000
-
1
tz.transition 1992, 1, :o2, 695764800
-
1
tz.transition 1992, 3, :o3, 701798400
-
1
tz.transition 1992, 9, :o2, 717519600
-
1
tz.transition 1993, 3, :o3, 733258800
-
1
tz.transition 1993, 5, :o4, 738086400
-
1
tz.transition 1993, 9, :o1, 748987200
-
1
tz.transition 1994, 3, :o4, 764712000
-
1
tz.transition 1994, 9, :o1, 780436800
-
1
tz.transition 1995, 3, :o4, 796161600
-
1
tz.transition 1995, 9, :o1, 811886400
-
1
tz.transition 1996, 3, :o4, 828216000
-
1
tz.transition 1996, 10, :o1, 846360000
-
1
tz.transition 1997, 3, :o4, 859665600
-
1
tz.transition 1997, 10, :o1, 877809600
-
1
tz.transition 1998, 3, :o4, 891115200
-
1
tz.transition 1998, 10, :o1, 909259200
-
1
tz.transition 1999, 3, :o4, 922564800
-
1
tz.transition 1999, 10, :o1, 941313600
-
1
tz.transition 2000, 3, :o4, 954014400
-
1
tz.transition 2000, 10, :o1, 972763200
-
1
tz.transition 2001, 3, :o4, 985464000
-
1
tz.transition 2001, 10, :o1, 1004212800
-
1
tz.transition 2002, 3, :o4, 1017518400
-
1
tz.transition 2002, 10, :o1, 1035662400
-
1
tz.transition 2003, 3, :o4, 1048968000
-
1
tz.transition 2003, 10, :o1, 1067112000
-
1
tz.transition 2004, 3, :o4, 1080417600
-
1
tz.transition 2004, 10, :o1, 1099166400
-
1
tz.transition 2005, 3, :o4, 1111867200
-
1
tz.transition 2005, 10, :o1, 1130616000
-
1
tz.transition 2006, 3, :o4, 1143316800
-
1
tz.transition 2006, 10, :o1, 1162065600
-
1
tz.transition 2007, 3, :o4, 1174766400
-
1
tz.transition 2007, 10, :o1, 1193515200
-
1
tz.transition 2008, 3, :o4, 1206820800
-
1
tz.transition 2008, 10, :o1, 1224964800
-
1
tz.transition 2009, 3, :o4, 1238270400
-
1
tz.transition 2009, 10, :o1, 1256414400
-
1
tz.transition 2010, 3, :o4, 1269720000
-
1
tz.transition 2010, 10, :o1, 1288468800
-
1
tz.transition 2011, 3, :o2, 1301169600
-
end
-
end
-
end
-
end
-
end
-
1
module TZInfo
-
1
module Definitions
-
1
module Asia
-
1
module Rangoon
-
1
include TimezoneDefinition
-
-
1
timezone 'Asia/Rangoon' do |tz|
-
1
tz.offset :o0, 23080, 0, :LMT
-
1
tz.offset :o1, 23076, 0, :RMT
-
1
tz.offset :o2, 23400, 0, :BURT
-
1
tz.offset :o3, 32400, 0, :JST
-
1
tz.offset :o4, 23400, 0, :MMT
-
-
1
tz.transition 1879, 12, :o1, 5200664903, 2160
-
1
tz.transition 1919, 12, :o2, 5813578159, 2400
-
1
tz.transition 1942, 4, :o3, 116663051, 48
-
1
tz.transition 1945, 5, :o4, 19452625, 8
-
end
-
end
-
end
-
end
-
end
-
1
module TZInfo
-
1
module Definitions
-
1
module Asia
-
1
module Riyadh
-
1
include TimezoneDefinition
-
-
1
timezone 'Asia/Riyadh' do |tz|
-
1
tz.offset :o0, 11212, 0, :LMT
-
1
tz.offset :o1, 10800, 0, :AST
-
-
1
tz.transition 1949, 12, :o1, 52558899197, 21600
-
end
-
end
-
end
-
end
-
end
-
1
module TZInfo
-
1
module Definitions
-
1
module Asia
-
1
module Seoul
-
1
include TimezoneDefinition
-
-
1
timezone 'Asia/Seoul' do |tz|
-
1
tz.offset :o0, 30472, 0, :LMT
-
1
tz.offset :o1, 30600, 0, :KST
-
1
tz.offset :o2, 32400, 0, :KST
-
1
tz.offset :o3, 28800, 0, :KST
-
1
tz.offset :o4, 28800, 3600, :KDT
-
1
tz.offset :o5, 32400, 3600, :KDT
-
-
1
tz.transition 1889, 12, :o1, 26042775991, 10800
-
1
tz.transition 1904, 11, :o2, 116007127, 48
-
1
tz.transition 1927, 12, :o1, 19401969, 8
-
1
tz.transition 1931, 12, :o2, 116481943, 48
-
1
tz.transition 1954, 3, :o3, 19478577, 8
-
1
tz.transition 1960, 5, :o4, 14622415, 6
-
1
tz.transition 1960, 9, :o3, 19497521, 8
-
1
tz.transition 1961, 8, :o1, 14625127, 6
-
1
tz.transition 1968, 9, :o2, 117126247, 48
-
1
tz.transition 1987, 5, :o5, 547570800
-
1
tz.transition 1987, 10, :o2, 560872800
-
1
tz.transition 1988, 5, :o5, 579020400
-
1
tz.transition 1988, 10, :o2, 592322400
-
end
-
end
-
end
-
end
-
end
-
1
module TZInfo
-
1
module Definitions
-
1
module Asia
-
1
module Shanghai
-
1
include TimezoneDefinition
-
-
1
timezone 'Asia/Shanghai' do |tz|
-
1
tz.offset :o0, 29152, 0, :LMT
-
1
tz.offset :o1, 28800, 0, :CST
-
1
tz.offset :o2, 28800, 3600, :CDT
-
-
1
tz.transition 1927, 12, :o1, 6548164639, 2700
-
1
tz.transition 1940, 6, :o2, 14578699, 6
-
1
tz.transition 1940, 9, :o1, 19439225, 8
-
1
tz.transition 1941, 3, :o2, 14580415, 6
-
1
tz.transition 1941, 9, :o1, 19442145, 8
-
1
tz.transition 1986, 5, :o2, 515520000
-
1
tz.transition 1986, 9, :o1, 527007600
-
1
tz.transition 1987, 4, :o2, 545155200
-
1
tz.transition 1987, 9, :o1, 558457200
-
1
tz.transition 1988, 4, :o2, 576604800
-
1
tz.transition 1988, 9, :o1, 589906800
-
1
tz.transition 1989, 4, :o2, 608659200
-
1
tz.transition 1989, 9, :o1, 621961200
-
1
tz.transition 1990, 4, :o2, 640108800
-
1
tz.transition 1990, 9, :o1, 653410800
-
1
tz.transition 1991, 4, :o2, 671558400
-
1
tz.transition 1991, 9, :o1, 684860400
-
end
-
end
-
end
-
end
-
end
-
1
module TZInfo
-
1
module Definitions
-
1
module Asia
-
1
module Singapore
-
1
include TimezoneDefinition
-
-
1
timezone 'Asia/Singapore' do |tz|
-
1
tz.offset :o0, 24925, 0, :LMT
-
1
tz.offset :o1, 24925, 0, :SMT
-
1
tz.offset :o2, 25200, 0, :MALT
-
1
tz.offset :o3, 25200, 1200, :MALST
-
1
tz.offset :o4, 26400, 0, :MALT
-
1
tz.offset :o5, 27000, 0, :MALT
-
1
tz.offset :o6, 32400, 0, :JST
-
1
tz.offset :o7, 27000, 0, :SGT
-
1
tz.offset :o8, 28800, 0, :SGT
-
-
1
tz.transition 1900, 12, :o1, 8347571291, 3456
-
1
tz.transition 1905, 5, :o2, 8353142363, 3456
-
1
tz.transition 1932, 12, :o3, 58249757, 24
-
1
tz.transition 1935, 12, :o4, 87414055, 36
-
1
tz.transition 1941, 8, :o5, 87488575, 36
-
1
tz.transition 1942, 2, :o6, 38886499, 16
-
1
tz.transition 1945, 9, :o5, 19453681, 8
-
1
tz.transition 1965, 8, :o7, 39023699, 16
-
1
tz.transition 1981, 12, :o8, 378664200
-
end
-
end
-
end
-
end
-
end
-
1
module TZInfo
-
1
module Definitions
-
1
module Asia
-
1
module Taipei
-
1
include TimezoneDefinition
-
-
1
timezone 'Asia/Taipei' do |tz|
-
1
tz.offset :o0, 29160, 0, :LMT
-
1
tz.offset :o1, 28800, 0, :CST
-
1
tz.offset :o2, 28800, 3600, :CDT
-
-
1
tz.transition 1895, 12, :o1, 193084733, 80
-
1
tz.transition 1945, 4, :o2, 14589457, 6
-
1
tz.transition 1945, 9, :o1, 19453833, 8
-
1
tz.transition 1946, 4, :o2, 14591647, 6
-
1
tz.transition 1946, 9, :o1, 19456753, 8
-
1
tz.transition 1947, 4, :o2, 14593837, 6
-
1
tz.transition 1947, 9, :o1, 19459673, 8
-
1
tz.transition 1948, 4, :o2, 14596033, 6
-
1
tz.transition 1948, 9, :o1, 19462601, 8
-
1
tz.transition 1949, 4, :o2, 14598223, 6
-
1
tz.transition 1949, 9, :o1, 19465521, 8
-
1
tz.transition 1950, 4, :o2, 14600413, 6
-
1
tz.transition 1950, 9, :o1, 19468441, 8
-
1
tz.transition 1951, 4, :o2, 14602603, 6
-
1
tz.transition 1951, 9, :o1, 19471361, 8
-
1
tz.transition 1952, 2, :o2, 14604433, 6
-
1
tz.transition 1952, 10, :o1, 19474537, 8
-
1
tz.transition 1953, 3, :o2, 14606809, 6
-
1
tz.transition 1953, 10, :o1, 19477457, 8
-
1
tz.transition 1954, 3, :o2, 14608999, 6
-
1
tz.transition 1954, 10, :o1, 19480377, 8
-
1
tz.transition 1955, 3, :o2, 14611189, 6
-
1
tz.transition 1955, 9, :o1, 19483049, 8
-
1
tz.transition 1956, 3, :o2, 14613385, 6
-
1
tz.transition 1956, 9, :o1, 19485977, 8
-
1
tz.transition 1957, 3, :o2, 14615575, 6
-
1
tz.transition 1957, 9, :o1, 19488897, 8
-
1
tz.transition 1958, 3, :o2, 14617765, 6
-
1
tz.transition 1958, 9, :o1, 19491817, 8
-
1
tz.transition 1959, 3, :o2, 14619955, 6
-
1
tz.transition 1959, 9, :o1, 19494737, 8
-
1
tz.transition 1960, 5, :o2, 14622517, 6
-
1
tz.transition 1960, 9, :o1, 19497665, 8
-
1
tz.transition 1961, 5, :o2, 14624707, 6
-
1
tz.transition 1961, 9, :o1, 19500585, 8
-
1
tz.transition 1974, 3, :o2, 133977600
-
1
tz.transition 1974, 9, :o1, 149785200
-
1
tz.transition 1975, 3, :o2, 165513600
-
1
tz.transition 1975, 9, :o1, 181321200
-
1
tz.transition 1979, 6, :o2, 299520000
-
1
tz.transition 1979, 9, :o1, 307465200
-
end
-
end
-
end
-
end
-
end
-
1
module TZInfo
-
1
module Definitions
-
1
module Asia
-
1
module Tashkent
-
1
include TimezoneDefinition
-
-
1
timezone 'Asia/Tashkent' do |tz|
-
1
tz.offset :o0, 16632, 0, :LMT
-
1
tz.offset :o1, 18000, 0, :TAST
-
1
tz.offset :o2, 21600, 0, :TAST
-
1
tz.offset :o3, 21600, 3600, :TASST
-
1
tz.offset :o4, 18000, 3600, :TASST
-
1
tz.offset :o5, 18000, 3600, :UZST
-
1
tz.offset :o6, 18000, 0, :UZT
-
-
1
tz.transition 1924, 5, :o1, 969562923, 400
-
1
tz.transition 1930, 6, :o2, 58227559, 24
-
1
tz.transition 1981, 3, :o3, 354909600
-
1
tz.transition 1981, 9, :o2, 370717200
-
1
tz.transition 1982, 3, :o3, 386445600
-
1
tz.transition 1982, 9, :o2, 402253200
-
1
tz.transition 1983, 3, :o3, 417981600
-
1
tz.transition 1983, 9, :o2, 433789200
-
1
tz.transition 1984, 3, :o3, 449604000
-
1
tz.transition 1984, 9, :o2, 465336000
-
1
tz.transition 1985, 3, :o3, 481060800
-
1
tz.transition 1985, 9, :o2, 496785600
-
1
tz.transition 1986, 3, :o3, 512510400
-
1
tz.transition 1986, 9, :o2, 528235200
-
1
tz.transition 1987, 3, :o3, 543960000
-
1
tz.transition 1987, 9, :o2, 559684800
-
1
tz.transition 1988, 3, :o3, 575409600
-
1
tz.transition 1988, 9, :o2, 591134400
-
1
tz.transition 1989, 3, :o3, 606859200
-
1
tz.transition 1989, 9, :o2, 622584000
-
1
tz.transition 1990, 3, :o3, 638308800
-
1
tz.transition 1990, 9, :o2, 654638400
-
1
tz.transition 1991, 3, :o4, 670363200
-
1
tz.transition 1991, 8, :o5, 683661600
-
1
tz.transition 1991, 9, :o6, 686091600
-
end
-
end
-
end
-
end
-
end
-
1
module TZInfo
-
1
module Definitions
-
1
module Asia
-
1
module Tbilisi
-
1
include TimezoneDefinition
-
-
1
timezone 'Asia/Tbilisi' do |tz|
-
1
tz.offset :o0, 10756, 0, :LMT
-
1
tz.offset :o1, 10756, 0, :TBMT
-
1
tz.offset :o2, 10800, 0, :TBIT
-
1
tz.offset :o3, 14400, 0, :TBIT
-
1
tz.offset :o4, 14400, 3600, :TBIST
-
1
tz.offset :o5, 10800, 3600, :TBIST
-
1
tz.offset :o6, 10800, 3600, :GEST
-
1
tz.offset :o7, 10800, 0, :GET
-
1
tz.offset :o8, 14400, 0, :GET
-
1
tz.offset :o9, 14400, 3600, :GEST
-
-
1
tz.transition 1879, 12, :o1, 52006652111, 21600
-
1
tz.transition 1924, 5, :o2, 52356399311, 21600
-
1
tz.transition 1957, 2, :o3, 19487187, 8
-
1
tz.transition 1981, 3, :o4, 354916800
-
1
tz.transition 1981, 9, :o3, 370724400
-
1
tz.transition 1982, 3, :o4, 386452800
-
1
tz.transition 1982, 9, :o3, 402260400
-
1
tz.transition 1983, 3, :o4, 417988800
-
1
tz.transition 1983, 9, :o3, 433796400
-
1
tz.transition 1984, 3, :o4, 449611200
-
1
tz.transition 1984, 9, :o3, 465343200
-
1
tz.transition 1985, 3, :o4, 481068000
-
1
tz.transition 1985, 9, :o3, 496792800
-
1
tz.transition 1986, 3, :o4, 512517600
-
1
tz.transition 1986, 9, :o3, 528242400
-
1
tz.transition 1987, 3, :o4, 543967200
-
1
tz.transition 1987, 9, :o3, 559692000
-
1
tz.transition 1988, 3, :o4, 575416800
-
1
tz.transition 1988, 9, :o3, 591141600
-
1
tz.transition 1989, 3, :o4, 606866400
-
1
tz.transition 1989, 9, :o3, 622591200
-
1
tz.transition 1990, 3, :o4, 638316000
-
1
tz.transition 1990, 9, :o3, 654645600
-
1
tz.transition 1991, 3, :o5, 670370400
-
1
tz.transition 1991, 4, :o6, 671140800
-
1
tz.transition 1991, 9, :o7, 686098800
-
1
tz.transition 1992, 3, :o6, 701816400
-
1
tz.transition 1992, 9, :o7, 717537600
-
1
tz.transition 1993, 3, :o6, 733266000
-
1
tz.transition 1993, 9, :o7, 748987200
-
1
tz.transition 1994, 3, :o6, 764715600
-
1
tz.transition 1994, 9, :o8, 780436800
-
1
tz.transition 1995, 3, :o9, 796161600
-
1
tz.transition 1995, 9, :o8, 811882800
-
1
tz.transition 1996, 3, :o9, 828216000
-
1
tz.transition 1997, 3, :o9, 859662000
-
1
tz.transition 1997, 10, :o8, 877806000
-
1
tz.transition 1998, 3, :o9, 891115200
-
1
tz.transition 1998, 10, :o8, 909255600
-
1
tz.transition 1999, 3, :o9, 922564800
-
1
tz.transition 1999, 10, :o8, 941310000
-
1
tz.transition 2000, 3, :o9, 954014400
-
1
tz.transition 2000, 10, :o8, 972759600
-
1
tz.transition 2001, 3, :o9, 985464000
-
1
tz.transition 2001, 10, :o8, 1004209200
-
1
tz.transition 2002, 3, :o9, 1017518400
-
1
tz.transition 2002, 10, :o8, 1035658800
-
1
tz.transition 2003, 3, :o9, 1048968000
-
1
tz.transition 2003, 10, :o8, 1067108400
-
1
tz.transition 2004, 3, :o9, 1080417600
-
1
tz.transition 2004, 6, :o6, 1088276400
-
1
tz.transition 2004, 10, :o7, 1099177200
-
1
tz.transition 2005, 3, :o8, 1111878000
-
end
-
end
-
end
-
end
-
end
-
1
module TZInfo
-
1
module Definitions
-
1
module Asia
-
1
module Tehran
-
1
include TimezoneDefinition
-
-
1
timezone 'Asia/Tehran' do |tz|
-
1
tz.offset :o0, 12344, 0, :LMT
-
1
tz.offset :o1, 12344, 0, :TMT
-
1
tz.offset :o2, 12600, 0, :IRST
-
1
tz.offset :o3, 14400, 0, :IRST
-
1
tz.offset :o4, 14400, 3600, :IRDT
-
1
tz.offset :o5, 12600, 3600, :IRDT
-
-
1
tz.transition 1915, 12, :o1, 26145324257, 10800
-
1
tz.transition 1945, 12, :o2, 26263670657, 10800
-
1
tz.transition 1977, 10, :o3, 247177800
-
1
tz.transition 1978, 3, :o4, 259272000
-
1
tz.transition 1978, 10, :o3, 277758000
-
1
tz.transition 1978, 12, :o2, 283982400
-
1
tz.transition 1979, 3, :o5, 290809800
-
1
tz.transition 1979, 9, :o2, 306531000
-
1
tz.transition 1980, 3, :o5, 322432200
-
1
tz.transition 1980, 9, :o2, 338499000
-
1
tz.transition 1991, 5, :o5, 673216200
-
1
tz.transition 1991, 9, :o2, 685481400
-
1
tz.transition 1992, 3, :o5, 701209800
-
1
tz.transition 1992, 9, :o2, 717103800
-
1
tz.transition 1993, 3, :o5, 732745800
-
1
tz.transition 1993, 9, :o2, 748639800
-
1
tz.transition 1994, 3, :o5, 764281800
-
1
tz.transition 1994, 9, :o2, 780175800
-
1
tz.transition 1995, 3, :o5, 795817800
-
1
tz.transition 1995, 9, :o2, 811711800
-
1
tz.transition 1996, 3, :o5, 827353800
-
1
tz.transition 1996, 9, :o2, 843247800
-
1
tz.transition 1997, 3, :o5, 858976200
-
1
tz.transition 1997, 9, :o2, 874870200
-
1
tz.transition 1998, 3, :o5, 890512200
-
1
tz.transition 1998, 9, :o2, 906406200
-
1
tz.transition 1999, 3, :o5, 922048200
-
1
tz.transition 1999, 9, :o2, 937942200
-
1
tz.transition 2000, 3, :o5, 953584200
-
1
tz.transition 2000, 9, :o2, 969478200
-
1
tz.transition 2001, 3, :o5, 985206600
-
1
tz.transition 2001, 9, :o2, 1001100600
-
1
tz.transition 2002, 3, :o5, 1016742600
-
1
tz.transition 2002, 9, :o2, 1032636600
-
1
tz.transition 2003, 3, :o5, 1048278600
-
1
tz.transition 2003, 9, :o2, 1064172600
-
1
tz.transition 2004, 3, :o5, 1079814600
-
1
tz.transition 2004, 9, :o2, 1095708600
-
1
tz.transition 2005, 3, :o5, 1111437000
-
1
tz.transition 2005, 9, :o2, 1127331000
-
1
tz.transition 2008, 3, :o5, 1206045000
-
1
tz.transition 2008, 9, :o2, 1221939000
-
1
tz.transition 2009, 3, :o5, 1237667400
-
1
tz.transition 2009, 9, :o2, 1253561400
-
1
tz.transition 2010, 3, :o5, 1269203400
-
1
tz.transition 2010, 9, :o2, 1285097400
-
1
tz.transition 2011, 3, :o5, 1300739400
-
1
tz.transition 2011, 9, :o2, 1316633400
-
1
tz.transition 2012, 3, :o5, 1332275400
-
1
tz.transition 2012, 9, :o2, 1348169400
-
1
tz.transition 2013, 3, :o5, 1363897800
-
1
tz.transition 2013, 9, :o2, 1379791800
-
1
tz.transition 2014, 3, :o5, 1395433800
-
1
tz.transition 2014, 9, :o2, 1411327800
-
1
tz.transition 2015, 3, :o5, 1426969800
-
1
tz.transition 2015, 9, :o2, 1442863800
-
1
tz.transition 2016, 3, :o5, 1458505800
-
1
tz.transition 2016, 9, :o2, 1474399800
-
1
tz.transition 2017, 3, :o5, 1490128200
-
1
tz.transition 2017, 9, :o2, 1506022200
-
1
tz.transition 2018, 3, :o5, 1521664200
-
1
tz.transition 2018, 9, :o2, 1537558200
-
1
tz.transition 2019, 3, :o5, 1553200200
-
1
tz.transition 2019, 9, :o2, 1569094200
-
1
tz.transition 2020, 3, :o5, 1584736200
-
1
tz.transition 2020, 9, :o2, 1600630200
-
1
tz.transition 2021, 3, :o5, 1616358600
-
1
tz.transition 2021, 9, :o2, 1632252600
-
1
tz.transition 2022, 3, :o5, 1647894600
-
1
tz.transition 2022, 9, :o2, 1663788600
-
1
tz.transition 2023, 3, :o5, 1679430600
-
1
tz.transition 2023, 9, :o2, 1695324600
-
1
tz.transition 2024, 3, :o5, 1710966600
-
1
tz.transition 2024, 9, :o2, 1726860600
-
1
tz.transition 2025, 3, :o5, 1742589000
-
1
tz.transition 2025, 9, :o2, 1758483000
-
1
tz.transition 2026, 3, :o5, 1774125000
-
1
tz.transition 2026, 9, :o2, 1790019000
-
1
tz.transition 2027, 3, :o5, 1805661000
-
1
tz.transition 2027, 9, :o2, 1821555000
-
1
tz.transition 2028, 3, :o5, 1837197000
-
1
tz.transition 2028, 9, :o2, 1853091000
-
1
tz.transition 2029, 3, :o5, 1868733000
-
1
tz.transition 2029, 9, :o2, 1884627000
-
1
tz.transition 2030, 3, :o5, 1900355400
-
1
tz.transition 2030, 9, :o2, 1916249400
-
1
tz.transition 2031, 3, :o5, 1931891400
-
1
tz.transition 2031, 9, :o2, 1947785400
-
1
tz.transition 2032, 3, :o5, 1963427400
-
1
tz.transition 2032, 9, :o2, 1979321400
-
1
tz.transition 2033, 3, :o5, 1994963400
-
1
tz.transition 2033, 9, :o2, 2010857400
-
1
tz.transition 2034, 3, :o5, 2026585800
-
1
tz.transition 2034, 9, :o2, 2042479800
-
1
tz.transition 2035, 3, :o5, 2058121800
-
1
tz.transition 2035, 9, :o2, 2074015800
-
1
tz.transition 2036, 3, :o5, 2089657800
-
1
tz.transition 2036, 9, :o2, 2105551800
-
1
tz.transition 2037, 3, :o5, 2121193800
-
1
tz.transition 2037, 9, :o2, 2137087800
-
end
-
end
-
end
-
end
-
end
-
1
module TZInfo
-
1
module Definitions
-
1
module Asia
-
1
module Tokyo
-
1
include TimezoneDefinition
-
-
1
timezone 'Asia/Tokyo' do |tz|
-
1
tz.offset :o0, 33539, 0, :LMT
-
1
tz.offset :o1, 32400, 0, :JST
-
1
tz.offset :o2, 32400, 0, :CJT
-
1
tz.offset :o3, 32400, 3600, :JDT
-
-
1
tz.transition 1887, 12, :o1, 19285097, 8
-
1
tz.transition 1895, 12, :o2, 19308473, 8
-
1
tz.transition 1937, 12, :o1, 19431193, 8
-
1
tz.transition 1948, 5, :o3, 58384157, 24
-
1
tz.transition 1948, 9, :o1, 14596831, 6
-
1
tz.transition 1949, 4, :o3, 58392221, 24
-
1
tz.transition 1949, 9, :o1, 14599015, 6
-
1
tz.transition 1950, 5, :o3, 58401797, 24
-
1
tz.transition 1950, 9, :o1, 14601199, 6
-
1
tz.transition 1951, 5, :o3, 58410533, 24
-
1
tz.transition 1951, 9, :o1, 14603383, 6
-
end
-
end
-
end
-
end
-
end
-
1
module TZInfo
-
1
module Definitions
-
1
module Asia
-
1
module Ulaanbaatar
-
1
include TimezoneDefinition
-
-
1
timezone 'Asia/Ulaanbaatar' do |tz|
-
1
tz.offset :o0, 25652, 0, :LMT
-
1
tz.offset :o1, 25200, 0, :ULAT
-
1
tz.offset :o2, 28800, 0, :ULAT
-
1
tz.offset :o3, 28800, 3600, :ULAST
-
-
1
tz.transition 1905, 7, :o1, 52208457187, 21600
-
1
tz.transition 1977, 12, :o2, 252435600
-
1
tz.transition 1983, 3, :o3, 417974400
-
1
tz.transition 1983, 9, :o2, 433782000
-
1
tz.transition 1984, 3, :o3, 449596800
-
1
tz.transition 1984, 9, :o2, 465318000
-
1
tz.transition 1985, 3, :o3, 481046400
-
1
tz.transition 1985, 9, :o2, 496767600
-
1
tz.transition 1986, 3, :o3, 512496000
-
1
tz.transition 1986, 9, :o2, 528217200
-
1
tz.transition 1987, 3, :o3, 543945600
-
1
tz.transition 1987, 9, :o2, 559666800
-
1
tz.transition 1988, 3, :o3, 575395200
-
1
tz.transition 1988, 9, :o2, 591116400
-
1
tz.transition 1989, 3, :o3, 606844800
-
1
tz.transition 1989, 9, :o2, 622566000
-
1
tz.transition 1990, 3, :o3, 638294400
-
1
tz.transition 1990, 9, :o2, 654620400
-
1
tz.transition 1991, 3, :o3, 670348800
-
1
tz.transition 1991, 9, :o2, 686070000
-
1
tz.transition 1992, 3, :o3, 701798400
-
1
tz.transition 1992, 9, :o2, 717519600
-
1
tz.transition 1993, 3, :o3, 733248000
-
1
tz.transition 1993, 9, :o2, 748969200
-
1
tz.transition 1994, 3, :o3, 764697600
-
1
tz.transition 1994, 9, :o2, 780418800
-
1
tz.transition 1995, 3, :o3, 796147200
-
1
tz.transition 1995, 9, :o2, 811868400
-
1
tz.transition 1996, 3, :o3, 828201600
-
1
tz.transition 1996, 9, :o2, 843922800
-
1
tz.transition 1997, 3, :o3, 859651200
-
1
tz.transition 1997, 9, :o2, 875372400
-
1
tz.transition 1998, 3, :o3, 891100800
-
1
tz.transition 1998, 9, :o2, 906822000
-
1
tz.transition 2001, 4, :o3, 988394400
-
1
tz.transition 2001, 9, :o2, 1001696400
-
1
tz.transition 2002, 3, :o3, 1017424800
-
1
tz.transition 2002, 9, :o2, 1033146000
-
1
tz.transition 2003, 3, :o3, 1048874400
-
1
tz.transition 2003, 9, :o2, 1064595600
-
1
tz.transition 2004, 3, :o3, 1080324000
-
1
tz.transition 2004, 9, :o2, 1096045200
-
1
tz.transition 2005, 3, :o3, 1111773600
-
1
tz.transition 2005, 9, :o2, 1127494800
-
1
tz.transition 2006, 3, :o3, 1143223200
-
1
tz.transition 2006, 9, :o2, 1159549200
-
end
-
end
-
end
-
end
-
end
-
1
module TZInfo
-
1
module Definitions
-
1
module Asia
-
1
module Urumqi
-
1
include TimezoneDefinition
-
-
1
timezone 'Asia/Urumqi' do |tz|
-
1
tz.offset :o0, 21020, 0, :LMT
-
1
tz.offset :o1, 21600, 0, :URUT
-
1
tz.offset :o2, 28800, 0, :CST
-
1
tz.offset :o3, 28800, 3600, :CDT
-
-
1
tz.transition 1927, 12, :o1, 10477063829, 4320
-
1
tz.transition 1980, 4, :o2, 325965600
-
1
tz.transition 1986, 5, :o3, 515520000
-
1
tz.transition 1986, 9, :o2, 527007600
-
1
tz.transition 1987, 4, :o3, 545155200
-
1
tz.transition 1987, 9, :o2, 558457200
-
1
tz.transition 1988, 4, :o3, 576604800
-
1
tz.transition 1988, 9, :o2, 589906800
-
1
tz.transition 1989, 4, :o3, 608659200
-
1
tz.transition 1989, 9, :o2, 621961200
-
1
tz.transition 1990, 4, :o3, 640108800
-
1
tz.transition 1990, 9, :o2, 653410800
-
1
tz.transition 1991, 4, :o3, 671558400
-
1
tz.transition 1991, 9, :o2, 684860400
-
end
-
end
-
end
-
end
-
end
-
1
module TZInfo
-
1
module Definitions
-
1
module Asia
-
1
module Vladivostok
-
1
include TimezoneDefinition
-
-
1
timezone 'Asia/Vladivostok' do |tz|
-
1
tz.offset :o0, 31664, 0, :LMT
-
1
tz.offset :o1, 32400, 0, :VLAT
-
1
tz.offset :o2, 36000, 0, :VLAT
-
1
tz.offset :o3, 36000, 3600, :VLAST
-
1
tz.offset :o4, 32400, 3600, :VLASST
-
1
tz.offset :o5, 32400, 0, :VLAST
-
1
tz.offset :o6, 39600, 0, :VLAT
-
-
1
tz.transition 1922, 11, :o1, 13086214921, 5400
-
1
tz.transition 1930, 6, :o2, 19409185, 8
-
1
tz.transition 1981, 3, :o3, 354895200
-
1
tz.transition 1981, 9, :o2, 370702800
-
1
tz.transition 1982, 3, :o3, 386431200
-
1
tz.transition 1982, 9, :o2, 402238800
-
1
tz.transition 1983, 3, :o3, 417967200
-
1
tz.transition 1983, 9, :o2, 433774800
-
1
tz.transition 1984, 3, :o3, 449589600
-
1
tz.transition 1984, 9, :o2, 465321600
-
1
tz.transition 1985, 3, :o3, 481046400
-
1
tz.transition 1985, 9, :o2, 496771200
-
1
tz.transition 1986, 3, :o3, 512496000
-
1
tz.transition 1986, 9, :o2, 528220800
-
1
tz.transition 1987, 3, :o3, 543945600
-
1
tz.transition 1987, 9, :o2, 559670400
-
1
tz.transition 1988, 3, :o3, 575395200
-
1
tz.transition 1988, 9, :o2, 591120000
-
1
tz.transition 1989, 3, :o3, 606844800
-
1
tz.transition 1989, 9, :o2, 622569600
-
1
tz.transition 1990, 3, :o3, 638294400
-
1
tz.transition 1990, 9, :o2, 654624000
-
1
tz.transition 1991, 3, :o4, 670348800
-
1
tz.transition 1991, 9, :o5, 686077200
-
1
tz.transition 1992, 1, :o2, 695754000
-
1
tz.transition 1992, 3, :o3, 701787600
-
1
tz.transition 1992, 9, :o2, 717508800
-
1
tz.transition 1993, 3, :o3, 733248000
-
1
tz.transition 1993, 9, :o2, 748972800
-
1
tz.transition 1994, 3, :o3, 764697600
-
1
tz.transition 1994, 9, :o2, 780422400
-
1
tz.transition 1995, 3, :o3, 796147200
-
1
tz.transition 1995, 9, :o2, 811872000
-
1
tz.transition 1996, 3, :o3, 828201600
-
1
tz.transition 1996, 10, :o2, 846345600
-
1
tz.transition 1997, 3, :o3, 859651200
-
1
tz.transition 1997, 10, :o2, 877795200
-
1
tz.transition 1998, 3, :o3, 891100800
-
1
tz.transition 1998, 10, :o2, 909244800
-
1
tz.transition 1999, 3, :o3, 922550400
-
1
tz.transition 1999, 10, :o2, 941299200
-
1
tz.transition 2000, 3, :o3, 954000000
-
1
tz.transition 2000, 10, :o2, 972748800
-
1
tz.transition 2001, 3, :o3, 985449600
-
1
tz.transition 2001, 10, :o2, 1004198400
-
1
tz.transition 2002, 3, :o3, 1017504000
-
1
tz.transition 2002, 10, :o2, 1035648000
-
1
tz.transition 2003, 3, :o3, 1048953600
-
1
tz.transition 2003, 10, :o2, 1067097600
-
1
tz.transition 2004, 3, :o3, 1080403200
-
1
tz.transition 2004, 10, :o2, 1099152000
-
1
tz.transition 2005, 3, :o3, 1111852800
-
1
tz.transition 2005, 10, :o2, 1130601600
-
1
tz.transition 2006, 3, :o3, 1143302400
-
1
tz.transition 2006, 10, :o2, 1162051200
-
1
tz.transition 2007, 3, :o3, 1174752000
-
1
tz.transition 2007, 10, :o2, 1193500800
-
1
tz.transition 2008, 3, :o3, 1206806400
-
1
tz.transition 2008, 10, :o2, 1224950400
-
1
tz.transition 2009, 3, :o3, 1238256000
-
1
tz.transition 2009, 10, :o2, 1256400000
-
1
tz.transition 2010, 3, :o3, 1269705600
-
1
tz.transition 2010, 10, :o2, 1288454400
-
1
tz.transition 2011, 3, :o6, 1301155200
-
end
-
end
-
end
-
end
-
end
-
1
module TZInfo
-
1
module Definitions
-
1
module Asia
-
1
module Yakutsk
-
1
include TimezoneDefinition
-
-
1
timezone 'Asia/Yakutsk' do |tz|
-
1
tz.offset :o0, 31120, 0, :LMT
-
1
tz.offset :o1, 28800, 0, :YAKT
-
1
tz.offset :o2, 32400, 0, :YAKT
-
1
tz.offset :o3, 32400, 3600, :YAKST
-
1
tz.offset :o4, 28800, 3600, :YAKST
-
1
tz.offset :o5, 36000, 0, :YAKT
-
-
1
tz.transition 1919, 12, :o1, 2616091711, 1080
-
1
tz.transition 1930, 6, :o2, 14556889, 6
-
1
tz.transition 1981, 3, :o3, 354898800
-
1
tz.transition 1981, 9, :o2, 370706400
-
1
tz.transition 1982, 3, :o3, 386434800
-
1
tz.transition 1982, 9, :o2, 402242400
-
1
tz.transition 1983, 3, :o3, 417970800
-
1
tz.transition 1983, 9, :o2, 433778400
-
1
tz.transition 1984, 3, :o3, 449593200
-
1
tz.transition 1984, 9, :o2, 465325200
-
1
tz.transition 1985, 3, :o3, 481050000
-
1
tz.transition 1985, 9, :o2, 496774800
-
1
tz.transition 1986, 3, :o3, 512499600
-
1
tz.transition 1986, 9, :o2, 528224400
-
1
tz.transition 1987, 3, :o3, 543949200
-
1
tz.transition 1987, 9, :o2, 559674000
-
1
tz.transition 1988, 3, :o3, 575398800
-
1
tz.transition 1988, 9, :o2, 591123600
-
1
tz.transition 1989, 3, :o3, 606848400
-
1
tz.transition 1989, 9, :o2, 622573200
-
1
tz.transition 1990, 3, :o3, 638298000
-
1
tz.transition 1990, 9, :o2, 654627600
-
1
tz.transition 1991, 3, :o4, 670352400
-
1
tz.transition 1991, 9, :o1, 686080800
-
1
tz.transition 1992, 1, :o2, 695757600
-
1
tz.transition 1992, 3, :o3, 701791200
-
1
tz.transition 1992, 9, :o2, 717512400
-
1
tz.transition 1993, 3, :o3, 733251600
-
1
tz.transition 1993, 9, :o2, 748976400
-
1
tz.transition 1994, 3, :o3, 764701200
-
1
tz.transition 1994, 9, :o2, 780426000
-
1
tz.transition 1995, 3, :o3, 796150800
-
1
tz.transition 1995, 9, :o2, 811875600
-
1
tz.transition 1996, 3, :o3, 828205200
-
1
tz.transition 1996, 10, :o2, 846349200
-
1
tz.transition 1997, 3, :o3, 859654800
-
1
tz.transition 1997, 10, :o2, 877798800
-
1
tz.transition 1998, 3, :o3, 891104400
-
1
tz.transition 1998, 10, :o2, 909248400
-
1
tz.transition 1999, 3, :o3, 922554000
-
1
tz.transition 1999, 10, :o2, 941302800
-
1
tz.transition 2000, 3, :o3, 954003600
-
1
tz.transition 2000, 10, :o2, 972752400
-
1
tz.transition 2001, 3, :o3, 985453200
-
1
tz.transition 2001, 10, :o2, 1004202000
-
1
tz.transition 2002, 3, :o3, 1017507600
-
1
tz.transition 2002, 10, :o2, 1035651600
-
1
tz.transition 2003, 3, :o3, 1048957200
-
1
tz.transition 2003, 10, :o2, 1067101200
-
1
tz.transition 2004, 3, :o3, 1080406800
-
1
tz.transition 2004, 10, :o2, 1099155600
-
1
tz.transition 2005, 3, :o3, 1111856400
-
1
tz.transition 2005, 10, :o2, 1130605200
-
1
tz.transition 2006, 3, :o3, 1143306000
-
1
tz.transition 2006, 10, :o2, 1162054800
-
1
tz.transition 2007, 3, :o3, 1174755600
-
1
tz.transition 2007, 10, :o2, 1193504400
-
1
tz.transition 2008, 3, :o3, 1206810000
-
1
tz.transition 2008, 10, :o2, 1224954000
-
1
tz.transition 2009, 3, :o3, 1238259600
-
1
tz.transition 2009, 10, :o2, 1256403600
-
1
tz.transition 2010, 3, :o3, 1269709200
-
1
tz.transition 2010, 10, :o2, 1288458000
-
1
tz.transition 2011, 3, :o5, 1301158800
-
end
-
end
-
end
-
end
-
end
-
1
module TZInfo
-
1
module Definitions
-
1
module Asia
-
1
module Yekaterinburg
-
1
include TimezoneDefinition
-
-
1
timezone 'Asia/Yekaterinburg' do |tz|
-
1
tz.offset :o0, 14544, 0, :LMT
-
1
tz.offset :o1, 14400, 0, :SVET
-
1
tz.offset :o2, 18000, 0, :SVET
-
1
tz.offset :o3, 18000, 3600, :SVEST
-
1
tz.offset :o4, 14400, 3600, :SVEST
-
1
tz.offset :o5, 18000, 0, :YEKT
-
1
tz.offset :o6, 18000, 3600, :YEKST
-
1
tz.offset :o7, 21600, 0, :YEKT
-
-
1
tz.transition 1919, 7, :o1, 1453292699, 600
-
1
tz.transition 1930, 6, :o2, 7278445, 3
-
1
tz.transition 1981, 3, :o3, 354913200
-
1
tz.transition 1981, 9, :o2, 370720800
-
1
tz.transition 1982, 3, :o3, 386449200
-
1
tz.transition 1982, 9, :o2, 402256800
-
1
tz.transition 1983, 3, :o3, 417985200
-
1
tz.transition 1983, 9, :o2, 433792800
-
1
tz.transition 1984, 3, :o3, 449607600
-
1
tz.transition 1984, 9, :o2, 465339600
-
1
tz.transition 1985, 3, :o3, 481064400
-
1
tz.transition 1985, 9, :o2, 496789200
-
1
tz.transition 1986, 3, :o3, 512514000
-
1
tz.transition 1986, 9, :o2, 528238800
-
1
tz.transition 1987, 3, :o3, 543963600
-
1
tz.transition 1987, 9, :o2, 559688400
-
1
tz.transition 1988, 3, :o3, 575413200
-
1
tz.transition 1988, 9, :o2, 591138000
-
1
tz.transition 1989, 3, :o3, 606862800
-
1
tz.transition 1989, 9, :o2, 622587600
-
1
tz.transition 1990, 3, :o3, 638312400
-
1
tz.transition 1990, 9, :o2, 654642000
-
1
tz.transition 1991, 3, :o4, 670366800
-
1
tz.transition 1991, 9, :o1, 686095200
-
1
tz.transition 1992, 1, :o5, 695772000
-
1
tz.transition 1992, 3, :o6, 701805600
-
1
tz.transition 1992, 9, :o5, 717526800
-
1
tz.transition 1993, 3, :o6, 733266000
-
1
tz.transition 1993, 9, :o5, 748990800
-
1
tz.transition 1994, 3, :o6, 764715600
-
1
tz.transition 1994, 9, :o5, 780440400
-
1
tz.transition 1995, 3, :o6, 796165200
-
1
tz.transition 1995, 9, :o5, 811890000
-
1
tz.transition 1996, 3, :o6, 828219600
-
1
tz.transition 1996, 10, :o5, 846363600
-
1
tz.transition 1997, 3, :o6, 859669200
-
1
tz.transition 1997, 10, :o5, 877813200
-
1
tz.transition 1998, 3, :o6, 891118800
-
1
tz.transition 1998, 10, :o5, 909262800
-
1
tz.transition 1999, 3, :o6, 922568400
-
1
tz.transition 1999, 10, :o5, 941317200
-
1
tz.transition 2000, 3, :o6, 954018000
-
1
tz.transition 2000, 10, :o5, 972766800
-
1
tz.transition 2001, 3, :o6, 985467600
-
1
tz.transition 2001, 10, :o5, 1004216400
-
1
tz.transition 2002, 3, :o6, 1017522000
-
1
tz.transition 2002, 10, :o5, 1035666000
-
1
tz.transition 2003, 3, :o6, 1048971600
-
1
tz.transition 2003, 10, :o5, 1067115600
-
1
tz.transition 2004, 3, :o6, 1080421200
-
1
tz.transition 2004, 10, :o5, 1099170000
-
1
tz.transition 2005, 3, :o6, 1111870800
-
1
tz.transition 2005, 10, :o5, 1130619600
-
1
tz.transition 2006, 3, :o6, 1143320400
-
1
tz.transition 2006, 10, :o5, 1162069200
-
1
tz.transition 2007, 3, :o6, 1174770000
-
1
tz.transition 2007, 10, :o5, 1193518800
-
1
tz.transition 2008, 3, :o6, 1206824400
-
1
tz.transition 2008, 10, :o5, 1224968400
-
1
tz.transition 2009, 3, :o6, 1238274000
-
1
tz.transition 2009, 10, :o5, 1256418000
-
1
tz.transition 2010, 3, :o6, 1269723600
-
1
tz.transition 2010, 10, :o5, 1288472400
-
1
tz.transition 2011, 3, :o7, 1301173200
-
end
-
end
-
end
-
end
-
end
-
1
module TZInfo
-
1
module Definitions
-
1
module Asia
-
1
module Yerevan
-
1
include TimezoneDefinition
-
-
1
timezone 'Asia/Yerevan' do |tz|
-
1
tz.offset :o0, 10680, 0, :LMT
-
1
tz.offset :o1, 10800, 0, :YERT
-
1
tz.offset :o2, 14400, 0, :YERT
-
1
tz.offset :o3, 14400, 3600, :YERST
-
1
tz.offset :o4, 10800, 3600, :YERST
-
1
tz.offset :o5, 10800, 3600, :AMST
-
1
tz.offset :o6, 10800, 0, :AMT
-
1
tz.offset :o7, 14400, 0, :AMT
-
1
tz.offset :o8, 14400, 3600, :AMST
-
-
1
tz.transition 1924, 5, :o1, 1745213311, 720
-
1
tz.transition 1957, 2, :o2, 19487187, 8
-
1
tz.transition 1981, 3, :o3, 354916800
-
1
tz.transition 1981, 9, :o2, 370724400
-
1
tz.transition 1982, 3, :o3, 386452800
-
1
tz.transition 1982, 9, :o2, 402260400
-
1
tz.transition 1983, 3, :o3, 417988800
-
1
tz.transition 1983, 9, :o2, 433796400
-
1
tz.transition 1984, 3, :o3, 449611200
-
1
tz.transition 1984, 9, :o2, 465343200
-
1
tz.transition 1985, 3, :o3, 481068000
-
1
tz.transition 1985, 9, :o2, 496792800
-
1
tz.transition 1986, 3, :o3, 512517600
-
1
tz.transition 1986, 9, :o2, 528242400
-
1
tz.transition 1987, 3, :o3, 543967200
-
1
tz.transition 1987, 9, :o2, 559692000
-
1
tz.transition 1988, 3, :o3, 575416800
-
1
tz.transition 1988, 9, :o2, 591141600
-
1
tz.transition 1989, 3, :o3, 606866400
-
1
tz.transition 1989, 9, :o2, 622591200
-
1
tz.transition 1990, 3, :o3, 638316000
-
1
tz.transition 1990, 9, :o2, 654645600
-
1
tz.transition 1991, 3, :o4, 670370400
-
1
tz.transition 1991, 9, :o5, 685569600
-
1
tz.transition 1991, 9, :o6, 686098800
-
1
tz.transition 1992, 3, :o5, 701812800
-
1
tz.transition 1992, 9, :o6, 717534000
-
1
tz.transition 1993, 3, :o5, 733273200
-
1
tz.transition 1993, 9, :o6, 748998000
-
1
tz.transition 1994, 3, :o5, 764722800
-
1
tz.transition 1994, 9, :o6, 780447600
-
1
tz.transition 1995, 3, :o5, 796172400
-
1
tz.transition 1995, 9, :o7, 811897200
-
1
tz.transition 1997, 3, :o8, 859672800
-
1
tz.transition 1997, 10, :o7, 877816800
-
1
tz.transition 1998, 3, :o8, 891122400
-
1
tz.transition 1998, 10, :o7, 909266400
-
1
tz.transition 1999, 3, :o8, 922572000
-
1
tz.transition 1999, 10, :o7, 941320800
-
1
tz.transition 2000, 3, :o8, 954021600
-
1
tz.transition 2000, 10, :o7, 972770400
-
1
tz.transition 2001, 3, :o8, 985471200
-
1
tz.transition 2001, 10, :o7, 1004220000
-
1
tz.transition 2002, 3, :o8, 1017525600
-
1
tz.transition 2002, 10, :o7, 1035669600
-
1
tz.transition 2003, 3, :o8, 1048975200
-
1
tz.transition 2003, 10, :o7, 1067119200
-
1
tz.transition 2004, 3, :o8, 1080424800
-
1
tz.transition 2004, 10, :o7, 1099173600
-
1
tz.transition 2005, 3, :o8, 1111874400
-
1
tz.transition 2005, 10, :o7, 1130623200
-
1
tz.transition 2006, 3, :o8, 1143324000
-
1
tz.transition 2006, 10, :o7, 1162072800
-
1
tz.transition 2007, 3, :o8, 1174773600
-
1
tz.transition 2007, 10, :o7, 1193522400
-
1
tz.transition 2008, 3, :o8, 1206828000
-
1
tz.transition 2008, 10, :o7, 1224972000
-
1
tz.transition 2009, 3, :o8, 1238277600
-
1
tz.transition 2009, 10, :o7, 1256421600
-
1
tz.transition 2010, 3, :o8, 1269727200
-
1
tz.transition 2010, 10, :o7, 1288476000
-
1
tz.transition 2011, 3, :o8, 1301176800
-
1
tz.transition 2011, 10, :o7, 1319925600
-
end
-
end
-
end
-
end
-
end
-
1
module TZInfo
-
1
module Definitions
-
1
module Atlantic
-
1
module Azores
-
1
include TimezoneDefinition
-
-
1
timezone 'Atlantic/Azores' do |tz|
-
1
tz.offset :o0, -6160, 0, :LMT
-
1
tz.offset :o1, -6872, 0, :HMT
-
1
tz.offset :o2, -7200, 0, :AZOT
-
1
tz.offset :o3, -7200, 3600, :AZOST
-
1
tz.offset :o4, -7200, 7200, :AZOMT
-
1
tz.offset :o5, -3600, 0, :AZOT
-
1
tz.offset :o6, -3600, 3600, :AZOST
-
1
tz.offset :o7, 0, 0, :WET
-
-
1
tz.transition 1884, 1, :o1, 2601910697, 1080
-
1
tz.transition 1911, 5, :o2, 26127150259, 10800
-
1
tz.transition 1916, 6, :o3, 58104781, 24
-
1
tz.transition 1916, 11, :o2, 29054023, 12
-
1
tz.transition 1917, 3, :o3, 58110925, 24
-
1
tz.transition 1917, 10, :o2, 58116397, 24
-
1
tz.transition 1918, 3, :o3, 58119709, 24
-
1
tz.transition 1918, 10, :o2, 58125157, 24
-
1
tz.transition 1919, 3, :o3, 58128445, 24
-
1
tz.transition 1919, 10, :o2, 58133917, 24
-
1
tz.transition 1920, 3, :o3, 58137229, 24
-
1
tz.transition 1920, 10, :o2, 58142701, 24
-
1
tz.transition 1921, 3, :o3, 58145989, 24
-
1
tz.transition 1921, 10, :o2, 58151461, 24
-
1
tz.transition 1924, 4, :o3, 58173421, 24
-
1
tz.transition 1924, 10, :o2, 58177765, 24
-
1
tz.transition 1926, 4, :o3, 58190965, 24
-
1
tz.transition 1926, 10, :o2, 58194997, 24
-
1
tz.transition 1927, 4, :o3, 58199533, 24
-
1
tz.transition 1927, 10, :o2, 58203733, 24
-
1
tz.transition 1928, 4, :o3, 58208437, 24
-
1
tz.transition 1928, 10, :o2, 58212637, 24
-
1
tz.transition 1929, 4, :o3, 58217341, 24
-
1
tz.transition 1929, 10, :o2, 58221373, 24
-
1
tz.transition 1931, 4, :o3, 58234813, 24
-
1
tz.transition 1931, 10, :o2, 58238845, 24
-
1
tz.transition 1932, 4, :o3, 58243213, 24
-
1
tz.transition 1932, 10, :o2, 58247581, 24
-
1
tz.transition 1934, 4, :o3, 58260853, 24
-
1
tz.transition 1934, 10, :o2, 58265221, 24
-
1
tz.transition 1935, 3, :o3, 58269421, 24
-
1
tz.transition 1935, 10, :o2, 58273957, 24
-
1
tz.transition 1936, 4, :o3, 58278661, 24
-
1
tz.transition 1936, 10, :o2, 58282693, 24
-
1
tz.transition 1937, 4, :o3, 58287061, 24
-
1
tz.transition 1937, 10, :o2, 58291429, 24
-
1
tz.transition 1938, 3, :o3, 58295629, 24
-
1
tz.transition 1938, 10, :o2, 58300165, 24
-
1
tz.transition 1939, 4, :o3, 58304869, 24
-
1
tz.transition 1939, 11, :o2, 58310077, 24
-
1
tz.transition 1940, 2, :o3, 58312429, 24
-
1
tz.transition 1940, 10, :o2, 58317805, 24
-
1
tz.transition 1941, 4, :o3, 58322173, 24
-
1
tz.transition 1941, 10, :o2, 58326565, 24
-
1
tz.transition 1942, 3, :o3, 58330405, 24
-
1
tz.transition 1942, 4, :o4, 4860951, 2
-
1
tz.transition 1942, 8, :o3, 4861175, 2
-
1
tz.transition 1942, 10, :o2, 58335781, 24
-
1
tz.transition 1943, 3, :o3, 58339141, 24
-
1
tz.transition 1943, 4, :o4, 4861665, 2
-
1
tz.transition 1943, 8, :o3, 4861931, 2
-
1
tz.transition 1943, 10, :o2, 58344685, 24
-
1
tz.transition 1944, 3, :o3, 58347877, 24
-
1
tz.transition 1944, 4, :o4, 4862407, 2
-
1
tz.transition 1944, 8, :o3, 4862659, 2
-
1
tz.transition 1944, 10, :o2, 58353421, 24
-
1
tz.transition 1945, 3, :o3, 58356613, 24
-
1
tz.transition 1945, 4, :o4, 4863135, 2
-
1
tz.transition 1945, 8, :o3, 4863387, 2
-
1
tz.transition 1945, 10, :o2, 58362157, 24
-
1
tz.transition 1946, 4, :o3, 58366021, 24
-
1
tz.transition 1946, 10, :o2, 58370389, 24
-
1
tz.transition 1947, 4, :o3, 7296845, 3
-
1
tz.transition 1947, 10, :o2, 7297391, 3
-
1
tz.transition 1948, 4, :o3, 7297937, 3
-
1
tz.transition 1948, 10, :o2, 7298483, 3
-
1
tz.transition 1949, 4, :o3, 7299029, 3
-
1
tz.transition 1949, 10, :o2, 7299575, 3
-
1
tz.transition 1951, 4, :o3, 7301213, 3
-
1
tz.transition 1951, 10, :o2, 7301780, 3
-
1
tz.transition 1952, 4, :o3, 7302326, 3
-
1
tz.transition 1952, 10, :o2, 7302872, 3
-
1
tz.transition 1953, 4, :o3, 7303418, 3
-
1
tz.transition 1953, 10, :o2, 7303964, 3
-
1
tz.transition 1954, 4, :o3, 7304510, 3
-
1
tz.transition 1954, 10, :o2, 7305056, 3
-
1
tz.transition 1955, 4, :o3, 7305602, 3
-
1
tz.transition 1955, 10, :o2, 7306148, 3
-
1
tz.transition 1956, 4, :o3, 7306694, 3
-
1
tz.transition 1956, 10, :o2, 7307261, 3
-
1
tz.transition 1957, 4, :o3, 7307807, 3
-
1
tz.transition 1957, 10, :o2, 7308353, 3
-
1
tz.transition 1958, 4, :o3, 7308899, 3
-
1
tz.transition 1958, 10, :o2, 7309445, 3
-
1
tz.transition 1959, 4, :o3, 7309991, 3
-
1
tz.transition 1959, 10, :o2, 7310537, 3
-
1
tz.transition 1960, 4, :o3, 7311083, 3
-
1
tz.transition 1960, 10, :o2, 7311629, 3
-
1
tz.transition 1961, 4, :o3, 7312175, 3
-
1
tz.transition 1961, 10, :o2, 7312721, 3
-
1
tz.transition 1962, 4, :o3, 7313267, 3
-
1
tz.transition 1962, 10, :o2, 7313834, 3
-
1
tz.transition 1963, 4, :o3, 7314380, 3
-
1
tz.transition 1963, 10, :o2, 7314926, 3
-
1
tz.transition 1964, 4, :o3, 7315472, 3
-
1
tz.transition 1964, 10, :o2, 7316018, 3
-
1
tz.transition 1965, 4, :o3, 7316564, 3
-
1
tz.transition 1965, 10, :o2, 7317110, 3
-
1
tz.transition 1966, 4, :o5, 7317656, 3
-
1
tz.transition 1977, 3, :o6, 228272400
-
1
tz.transition 1977, 9, :o5, 243997200
-
1
tz.transition 1978, 4, :o6, 260326800
-
1
tz.transition 1978, 10, :o5, 276051600
-
1
tz.transition 1979, 4, :o6, 291776400
-
1
tz.transition 1979, 9, :o5, 307504800
-
1
tz.transition 1980, 3, :o6, 323226000
-
1
tz.transition 1980, 9, :o5, 338954400
-
1
tz.transition 1981, 3, :o6, 354679200
-
1
tz.transition 1981, 9, :o5, 370404000
-
1
tz.transition 1982, 3, :o6, 386128800
-
1
tz.transition 1982, 9, :o5, 401853600
-
1
tz.transition 1983, 3, :o6, 417582000
-
1
tz.transition 1983, 9, :o5, 433303200
-
1
tz.transition 1984, 3, :o6, 449028000
-
1
tz.transition 1984, 9, :o5, 465357600
-
1
tz.transition 1985, 3, :o6, 481082400
-
1
tz.transition 1985, 9, :o5, 496807200
-
1
tz.transition 1986, 3, :o6, 512532000
-
1
tz.transition 1986, 9, :o5, 528256800
-
1
tz.transition 1987, 3, :o6, 543981600
-
1
tz.transition 1987, 9, :o5, 559706400
-
1
tz.transition 1988, 3, :o6, 575431200
-
1
tz.transition 1988, 9, :o5, 591156000
-
1
tz.transition 1989, 3, :o6, 606880800
-
1
tz.transition 1989, 9, :o5, 622605600
-
1
tz.transition 1990, 3, :o6, 638330400
-
1
tz.transition 1990, 9, :o5, 654660000
-
1
tz.transition 1991, 3, :o6, 670384800
-
1
tz.transition 1991, 9, :o5, 686109600
-
1
tz.transition 1992, 3, :o6, 701834400
-
1
tz.transition 1992, 9, :o7, 717559200
-
1
tz.transition 1993, 3, :o6, 733280400
-
1
tz.transition 1993, 9, :o5, 749005200
-
1
tz.transition 1994, 3, :o6, 764730000
-
1
tz.transition 1994, 9, :o5, 780454800
-
1
tz.transition 1995, 3, :o6, 796179600
-
1
tz.transition 1995, 9, :o5, 811904400
-
1
tz.transition 1996, 3, :o6, 828234000
-
1
tz.transition 1996, 10, :o5, 846378000
-
1
tz.transition 1997, 3, :o6, 859683600
-
1
tz.transition 1997, 10, :o5, 877827600
-
1
tz.transition 1998, 3, :o6, 891133200
-
1
tz.transition 1998, 10, :o5, 909277200
-
1
tz.transition 1999, 3, :o6, 922582800
-
1
tz.transition 1999, 10, :o5, 941331600
-
1
tz.transition 2000, 3, :o6, 954032400
-
1
tz.transition 2000, 10, :o5, 972781200
-
1
tz.transition 2001, 3, :o6, 985482000
-
1
tz.transition 2001, 10, :o5, 1004230800
-
1
tz.transition 2002, 3, :o6, 1017536400
-
1
tz.transition 2002, 10, :o5, 1035680400
-
1
tz.transition 2003, 3, :o6, 1048986000
-
1
tz.transition 2003, 10, :o5, 1067130000
-
1
tz.transition 2004, 3, :o6, 1080435600
-
1
tz.transition 2004, 10, :o5, 1099184400
-
1
tz.transition 2005, 3, :o6, 1111885200
-
1
tz.transition 2005, 10, :o5, 1130634000
-
1
tz.transition 2006, 3, :o6, 1143334800
-
1
tz.transition 2006, 10, :o5, 1162083600
-
1
tz.transition 2007, 3, :o6, 1174784400
-
1
tz.transition 2007, 10, :o5, 1193533200
-
1
tz.transition 2008, 3, :o6, 1206838800
-
1
tz.transition 2008, 10, :o5, 1224982800
-
1
tz.transition 2009, 3, :o6, 1238288400
-
1
tz.transition 2009, 10, :o5, 1256432400
-
1
tz.transition 2010, 3, :o6, 1269738000
-
1
tz.transition 2010, 10, :o5, 1288486800
-
1
tz.transition 2011, 3, :o6, 1301187600
-
1
tz.transition 2011, 10, :o5, 1319936400
-
1
tz.transition 2012, 3, :o6, 1332637200
-
1
tz.transition 2012, 10, :o5, 1351386000
-
1
tz.transition 2013, 3, :o6, 1364691600
-
1
tz.transition 2013, 10, :o5, 1382835600
-
1
tz.transition 2014, 3, :o6, 1396141200
-
1
tz.transition 2014, 10, :o5, 1414285200
-
1
tz.transition 2015, 3, :o6, 1427590800
-
1
tz.transition 2015, 10, :o5, 1445734800
-
1
tz.transition 2016, 3, :o6, 1459040400
-
1
tz.transition 2016, 10, :o5, 1477789200
-
1
tz.transition 2017, 3, :o6, 1490490000
-
1
tz.transition 2017, 10, :o5, 1509238800
-
1
tz.transition 2018, 3, :o6, 1521939600
-
1
tz.transition 2018, 10, :o5, 1540688400
-
1
tz.transition 2019, 3, :o6, 1553994000
-
1
tz.transition 2019, 10, :o5, 1572138000
-
1
tz.transition 2020, 3, :o6, 1585443600
-
1
tz.transition 2020, 10, :o5, 1603587600
-
1
tz.transition 2021, 3, :o6, 1616893200
-
1
tz.transition 2021, 10, :o5, 1635642000
-
1
tz.transition 2022, 3, :o6, 1648342800
-
1
tz.transition 2022, 10, :o5, 1667091600
-
1
tz.transition 2023, 3, :o6, 1679792400
-
1
tz.transition 2023, 10, :o5, 1698541200
-
1
tz.transition 2024, 3, :o6, 1711846800
-
1
tz.transition 2024, 10, :o5, 1729990800
-
1
tz.transition 2025, 3, :o6, 1743296400
-
1
tz.transition 2025, 10, :o5, 1761440400
-
1
tz.transition 2026, 3, :o6, 1774746000
-
1
tz.transition 2026, 10, :o5, 1792890000
-
1
tz.transition 2027, 3, :o6, 1806195600
-
1
tz.transition 2027, 10, :o5, 1824944400
-
1
tz.transition 2028, 3, :o6, 1837645200
-
1
tz.transition 2028, 10, :o5, 1856394000
-
1
tz.transition 2029, 3, :o6, 1869094800
-
1
tz.transition 2029, 10, :o5, 1887843600
-
1
tz.transition 2030, 3, :o6, 1901149200
-
1
tz.transition 2030, 10, :o5, 1919293200
-
1
tz.transition 2031, 3, :o6, 1932598800
-
1
tz.transition 2031, 10, :o5, 1950742800
-
1
tz.transition 2032, 3, :o6, 1964048400
-
1
tz.transition 2032, 10, :o5, 1982797200
-
1
tz.transition 2033, 3, :o6, 1995498000
-
1
tz.transition 2033, 10, :o5, 2014246800
-
1
tz.transition 2034, 3, :o6, 2026947600
-
1
tz.transition 2034, 10, :o5, 2045696400
-
1
tz.transition 2035, 3, :o6, 2058397200
-
1
tz.transition 2035, 10, :o5, 2077146000
-
1
tz.transition 2036, 3, :o6, 2090451600
-
1
tz.transition 2036, 10, :o5, 2108595600
-
1
tz.transition 2037, 3, :o6, 2121901200
-
1
tz.transition 2037, 10, :o5, 2140045200
-
1
tz.transition 2038, 3, :o6, 59172253, 24
-
1
tz.transition 2038, 10, :o5, 59177461, 24
-
1
tz.transition 2039, 3, :o6, 59180989, 24
-
1
tz.transition 2039, 10, :o5, 59186197, 24
-
1
tz.transition 2040, 3, :o6, 59189725, 24
-
1
tz.transition 2040, 10, :o5, 59194933, 24
-
1
tz.transition 2041, 3, :o6, 59198629, 24
-
1
tz.transition 2041, 10, :o5, 59203669, 24
-
1
tz.transition 2042, 3, :o6, 59207365, 24
-
1
tz.transition 2042, 10, :o5, 59212405, 24
-
1
tz.transition 2043, 3, :o6, 59216101, 24
-
1
tz.transition 2043, 10, :o5, 59221141, 24
-
1
tz.transition 2044, 3, :o6, 59224837, 24
-
1
tz.transition 2044, 10, :o5, 59230045, 24
-
1
tz.transition 2045, 3, :o6, 59233573, 24
-
1
tz.transition 2045, 10, :o5, 59238781, 24
-
1
tz.transition 2046, 3, :o6, 59242309, 24
-
1
tz.transition 2046, 10, :o5, 59247517, 24
-
1
tz.transition 2047, 3, :o6, 59251213, 24
-
1
tz.transition 2047, 10, :o5, 59256253, 24
-
1
tz.transition 2048, 3, :o6, 59259949, 24
-
1
tz.transition 2048, 10, :o5, 59264989, 24
-
1
tz.transition 2049, 3, :o6, 59268685, 24
-
1
tz.transition 2049, 10, :o5, 59273893, 24
-
1
tz.transition 2050, 3, :o6, 59277421, 24
-
1
tz.transition 2050, 10, :o5, 59282629, 24
-
end
-
end
-
end
-
end
-
end
-
1
module TZInfo
-
1
module Definitions
-
1
module Atlantic
-
1
module Cape_Verde
-
1
include TimezoneDefinition
-
-
1
timezone 'Atlantic/Cape_Verde' do |tz|
-
1
tz.offset :o0, -5644, 0, :LMT
-
1
tz.offset :o1, -7200, 0, :CVT
-
1
tz.offset :o2, -7200, 3600, :CVST
-
1
tz.offset :o3, -3600, 0, :CVT
-
-
1
tz.transition 1907, 1, :o1, 52219653811, 21600
-
1
tz.transition 1942, 9, :o2, 29167243, 12
-
1
tz.transition 1945, 10, :o1, 58361845, 24
-
1
tz.transition 1975, 11, :o3, 186120000
-
end
-
end
-
end
-
end
-
end
-
1
module TZInfo
-
1
module Definitions
-
1
module Atlantic
-
1
module South_Georgia
-
1
include TimezoneDefinition
-
-
1
timezone 'Atlantic/South_Georgia' do |tz|
-
1
tz.offset :o0, -8768, 0, :LMT
-
1
tz.offset :o1, -7200, 0, :GST
-
-
1
tz.transition 1890, 1, :o1, 1627673806, 675
-
end
-
end
-
end
-
end
-
end
-
1
module TZInfo
-
1
module Definitions
-
1
module Australia
-
1
module Adelaide
-
1
include TimezoneDefinition
-
-
1
timezone 'Australia/Adelaide' do |tz|
-
1
tz.offset :o0, 33260, 0, :LMT
-
1
tz.offset :o1, 32400, 0, :CST
-
1
tz.offset :o2, 34200, 0, :CST
-
1
tz.offset :o3, 34200, 3600, :CST
-
-
1
tz.transition 1895, 1, :o1, 10425132497, 4320
-
1
tz.transition 1899, 4, :o2, 19318201, 8
-
1
tz.transition 1916, 12, :o3, 3486569911, 1440
-
1
tz.transition 1917, 3, :o2, 116222983, 48
-
1
tz.transition 1941, 12, :o3, 38885763, 16
-
1
tz.transition 1942, 3, :o2, 116661463, 48
-
1
tz.transition 1942, 9, :o3, 38890067, 16
-
1
tz.transition 1943, 3, :o2, 116678935, 48
-
1
tz.transition 1943, 10, :o3, 38896003, 16
-
1
tz.transition 1944, 3, :o2, 116696407, 48
-
1
tz.transition 1971, 10, :o3, 57688200
-
1
tz.transition 1972, 2, :o2, 67969800
-
1
tz.transition 1972, 10, :o3, 89137800
-
1
tz.transition 1973, 3, :o2, 100024200
-
1
tz.transition 1973, 10, :o3, 120587400
-
1
tz.transition 1974, 3, :o2, 131473800
-
1
tz.transition 1974, 10, :o3, 152037000
-
1
tz.transition 1975, 3, :o2, 162923400
-
1
tz.transition 1975, 10, :o3, 183486600
-
1
tz.transition 1976, 3, :o2, 194977800
-
1
tz.transition 1976, 10, :o3, 215541000
-
1
tz.transition 1977, 3, :o2, 226427400
-
1
tz.transition 1977, 10, :o3, 246990600
-
1
tz.transition 1978, 3, :o2, 257877000
-
1
tz.transition 1978, 10, :o3, 278440200
-
1
tz.transition 1979, 3, :o2, 289326600
-
1
tz.transition 1979, 10, :o3, 309889800
-
1
tz.transition 1980, 3, :o2, 320776200
-
1
tz.transition 1980, 10, :o3, 341339400
-
1
tz.transition 1981, 2, :o2, 352225800
-
1
tz.transition 1981, 10, :o3, 372789000
-
1
tz.transition 1982, 3, :o2, 384280200
-
1
tz.transition 1982, 10, :o3, 404843400
-
1
tz.transition 1983, 3, :o2, 415729800
-
1
tz.transition 1983, 10, :o3, 436293000
-
1
tz.transition 1984, 3, :o2, 447179400
-
1
tz.transition 1984, 10, :o3, 467742600
-
1
tz.transition 1985, 3, :o2, 478629000
-
1
tz.transition 1985, 10, :o3, 499192200
-
1
tz.transition 1986, 3, :o2, 511288200
-
1
tz.transition 1986, 10, :o3, 530037000
-
1
tz.transition 1987, 3, :o2, 542737800
-
1
tz.transition 1987, 10, :o3, 562091400
-
1
tz.transition 1988, 3, :o2, 574792200
-
1
tz.transition 1988, 10, :o3, 594145800
-
1
tz.transition 1989, 3, :o2, 606241800
-
1
tz.transition 1989, 10, :o3, 625595400
-
1
tz.transition 1990, 3, :o2, 637691400
-
1
tz.transition 1990, 10, :o3, 657045000
-
1
tz.transition 1991, 3, :o2, 667931400
-
1
tz.transition 1991, 10, :o3, 688494600
-
1
tz.transition 1992, 3, :o2, 701195400
-
1
tz.transition 1992, 10, :o3, 719944200
-
1
tz.transition 1993, 3, :o2, 731435400
-
1
tz.transition 1993, 10, :o3, 751998600
-
1
tz.transition 1994, 3, :o2, 764094600
-
1
tz.transition 1994, 10, :o3, 783448200
-
1
tz.transition 1995, 3, :o2, 796149000
-
1
tz.transition 1995, 10, :o3, 814897800
-
1
tz.transition 1996, 3, :o2, 828203400
-
1
tz.transition 1996, 10, :o3, 846347400
-
1
tz.transition 1997, 3, :o2, 859653000
-
1
tz.transition 1997, 10, :o3, 877797000
-
1
tz.transition 1998, 3, :o2, 891102600
-
1
tz.transition 1998, 10, :o3, 909246600
-
1
tz.transition 1999, 3, :o2, 922552200
-
1
tz.transition 1999, 10, :o3, 941301000
-
1
tz.transition 2000, 3, :o2, 954001800
-
1
tz.transition 2000, 10, :o3, 972750600
-
1
tz.transition 2001, 3, :o2, 985451400
-
1
tz.transition 2001, 10, :o3, 1004200200
-
1
tz.transition 2002, 3, :o2, 1017505800
-
1
tz.transition 2002, 10, :o3, 1035649800
-
1
tz.transition 2003, 3, :o2, 1048955400
-
1
tz.transition 2003, 10, :o3, 1067099400
-
1
tz.transition 2004, 3, :o2, 1080405000
-
1
tz.transition 2004, 10, :o3, 1099153800
-
1
tz.transition 2005, 3, :o2, 1111854600
-
1
tz.transition 2005, 10, :o3, 1130603400
-
1
tz.transition 2006, 4, :o2, 1143909000
-
1
tz.transition 2006, 10, :o3, 1162053000
-
1
tz.transition 2007, 3, :o2, 1174753800
-
1
tz.transition 2007, 10, :o3, 1193502600
-
1
tz.transition 2008, 4, :o2, 1207413000
-
1
tz.transition 2008, 10, :o3, 1223137800
-
1
tz.transition 2009, 4, :o2, 1238862600
-
1
tz.transition 2009, 10, :o3, 1254587400
-
1
tz.transition 2010, 4, :o2, 1270312200
-
1
tz.transition 2010, 10, :o3, 1286037000
-
1
tz.transition 2011, 4, :o2, 1301761800
-
1
tz.transition 2011, 10, :o3, 1317486600
-
1
tz.transition 2012, 3, :o2, 1333211400
-
1
tz.transition 2012, 10, :o3, 1349541000
-
1
tz.transition 2013, 4, :o2, 1365265800
-
1
tz.transition 2013, 10, :o3, 1380990600
-
1
tz.transition 2014, 4, :o2, 1396715400
-
1
tz.transition 2014, 10, :o3, 1412440200
-
1
tz.transition 2015, 4, :o2, 1428165000
-
1
tz.transition 2015, 10, :o3, 1443889800
-
1
tz.transition 2016, 4, :o2, 1459614600
-
1
tz.transition 2016, 10, :o3, 1475339400
-
1
tz.transition 2017, 4, :o2, 1491064200
-
1
tz.transition 2017, 9, :o3, 1506789000
-
1
tz.transition 2018, 3, :o2, 1522513800
-
1
tz.transition 2018, 10, :o3, 1538843400
-
1
tz.transition 2019, 4, :o2, 1554568200
-
1
tz.transition 2019, 10, :o3, 1570293000
-
1
tz.transition 2020, 4, :o2, 1586017800
-
1
tz.transition 2020, 10, :o3, 1601742600
-
1
tz.transition 2021, 4, :o2, 1617467400
-
1
tz.transition 2021, 10, :o3, 1633192200
-
1
tz.transition 2022, 4, :o2, 1648917000
-
1
tz.transition 2022, 10, :o3, 1664641800
-
1
tz.transition 2023, 4, :o2, 1680366600
-
1
tz.transition 2023, 9, :o3, 1696091400
-
1
tz.transition 2024, 4, :o2, 1712421000
-
1
tz.transition 2024, 10, :o3, 1728145800
-
1
tz.transition 2025, 4, :o2, 1743870600
-
1
tz.transition 2025, 10, :o3, 1759595400
-
1
tz.transition 2026, 4, :o2, 1775320200
-
1
tz.transition 2026, 10, :o3, 1791045000
-
1
tz.transition 2027, 4, :o2, 1806769800
-
1
tz.transition 2027, 10, :o3, 1822494600
-
1
tz.transition 2028, 4, :o2, 1838219400
-
1
tz.transition 2028, 9, :o3, 1853944200
-
1
tz.transition 2029, 3, :o2, 1869669000
-
1
tz.transition 2029, 10, :o3, 1885998600
-
1
tz.transition 2030, 4, :o2, 1901723400
-
1
tz.transition 2030, 10, :o3, 1917448200
-
1
tz.transition 2031, 4, :o2, 1933173000
-
1
tz.transition 2031, 10, :o3, 1948897800
-
1
tz.transition 2032, 4, :o2, 1964622600
-
1
tz.transition 2032, 10, :o3, 1980347400
-
1
tz.transition 2033, 4, :o2, 1996072200
-
1
tz.transition 2033, 10, :o3, 2011797000
-
1
tz.transition 2034, 4, :o2, 2027521800
-
1
tz.transition 2034, 9, :o3, 2043246600
-
1
tz.transition 2035, 3, :o2, 2058971400
-
1
tz.transition 2035, 10, :o3, 2075301000
-
1
tz.transition 2036, 4, :o2, 2091025800
-
1
tz.transition 2036, 10, :o3, 2106750600
-
1
tz.transition 2037, 4, :o2, 2122475400
-
1
tz.transition 2037, 10, :o3, 2138200200
-
1
tz.transition 2038, 4, :o2, 39448275, 16
-
1
tz.transition 2038, 10, :o3, 39451187, 16
-
1
tz.transition 2039, 4, :o2, 39454099, 16
-
1
tz.transition 2039, 10, :o3, 39457011, 16
-
1
tz.transition 2040, 3, :o2, 39459923, 16
-
1
tz.transition 2040, 10, :o3, 39462947, 16
-
1
tz.transition 2041, 4, :o2, 39465859, 16
-
1
tz.transition 2041, 10, :o3, 39468771, 16
-
1
tz.transition 2042, 4, :o2, 39471683, 16
-
1
tz.transition 2042, 10, :o3, 39474595, 16
-
1
tz.transition 2043, 4, :o2, 39477507, 16
-
1
tz.transition 2043, 10, :o3, 39480419, 16
-
1
tz.transition 2044, 4, :o2, 39483331, 16
-
1
tz.transition 2044, 10, :o3, 39486243, 16
-
1
tz.transition 2045, 4, :o2, 39489155, 16
-
1
tz.transition 2045, 9, :o3, 39492067, 16
-
1
tz.transition 2046, 3, :o2, 39494979, 16
-
1
tz.transition 2046, 10, :o3, 39498003, 16
-
1
tz.transition 2047, 4, :o2, 39500915, 16
-
1
tz.transition 2047, 10, :o3, 39503827, 16
-
1
tz.transition 2048, 4, :o2, 39506739, 16
-
1
tz.transition 2048, 10, :o3, 39509651, 16
-
1
tz.transition 2049, 4, :o2, 39512563, 16
-
1
tz.transition 2049, 10, :o3, 39515475, 16
-
1
tz.transition 2050, 4, :o2, 39518387, 16
-
end
-
end
-
end
-
end
-
end
-
1
module TZInfo
-
1
module Definitions
-
1
module Australia
-
1
module Brisbane
-
1
include TimezoneDefinition
-
-
1
timezone 'Australia/Brisbane' do |tz|
-
1
tz.offset :o0, 36728, 0, :LMT
-
1
tz.offset :o1, 36000, 0, :EST
-
1
tz.offset :o2, 36000, 3600, :EST
-
-
1
tz.transition 1894, 12, :o1, 26062496009, 10800
-
1
tz.transition 1916, 12, :o2, 3486569881, 1440
-
1
tz.transition 1917, 3, :o1, 19370497, 8
-
1
tz.transition 1941, 12, :o2, 14582161, 6
-
1
tz.transition 1942, 3, :o1, 19443577, 8
-
1
tz.transition 1942, 9, :o2, 14583775, 6
-
1
tz.transition 1943, 3, :o1, 19446489, 8
-
1
tz.transition 1943, 10, :o2, 14586001, 6
-
1
tz.transition 1944, 3, :o1, 19449401, 8
-
1
tz.transition 1971, 10, :o2, 57686400
-
1
tz.transition 1972, 2, :o1, 67968000
-
1
tz.transition 1989, 10, :o2, 625593600
-
1
tz.transition 1990, 3, :o1, 636480000
-
1
tz.transition 1990, 10, :o2, 657043200
-
1
tz.transition 1991, 3, :o1, 667929600
-
1
tz.transition 1991, 10, :o2, 688492800
-
1
tz.transition 1992, 2, :o1, 699379200
-
end
-
end
-
end
-
end
-
end
-
1
module TZInfo
-
1
module Definitions
-
1
module Australia
-
1
module Darwin
-
1
include TimezoneDefinition
-
-
1
timezone 'Australia/Darwin' do |tz|
-
1
tz.offset :o0, 31400, 0, :LMT
-
1
tz.offset :o1, 32400, 0, :CST
-
1
tz.offset :o2, 34200, 0, :CST
-
1
tz.offset :o3, 34200, 3600, :CST
-
-
1
tz.transition 1895, 1, :o1, 1042513259, 432
-
1
tz.transition 1899, 4, :o2, 19318201, 8
-
1
tz.transition 1916, 12, :o3, 3486569911, 1440
-
1
tz.transition 1917, 3, :o2, 116222983, 48
-
1
tz.transition 1941, 12, :o3, 38885763, 16
-
1
tz.transition 1942, 3, :o2, 116661463, 48
-
1
tz.transition 1942, 9, :o3, 38890067, 16
-
1
tz.transition 1943, 3, :o2, 116678935, 48
-
1
tz.transition 1943, 10, :o3, 38896003, 16
-
1
tz.transition 1944, 3, :o2, 116696407, 48
-
end
-
end
-
end
-
end
-
end
-
1
module TZInfo
-
1
module Definitions
-
1
module Australia
-
1
module Hobart
-
1
include TimezoneDefinition
-
-
1
timezone 'Australia/Hobart' do |tz|
-
1
tz.offset :o0, 35356, 0, :LMT
-
1
tz.offset :o1, 36000, 0, :EST
-
1
tz.offset :o2, 36000, 3600, :EST
-
-
1
tz.transition 1895, 8, :o1, 52130241161, 21600
-
1
tz.transition 1916, 9, :o2, 14526823, 6
-
1
tz.transition 1917, 3, :o1, 19370497, 8
-
1
tz.transition 1941, 12, :o2, 14582161, 6
-
1
tz.transition 1942, 3, :o1, 19443577, 8
-
1
tz.transition 1942, 9, :o2, 14583775, 6
-
1
tz.transition 1943, 3, :o1, 19446489, 8
-
1
tz.transition 1943, 10, :o2, 14586001, 6
-
1
tz.transition 1944, 3, :o1, 19449401, 8
-
1
tz.transition 1967, 9, :o2, 14638585, 6
-
1
tz.transition 1968, 3, :o1, 14639677, 6
-
1
tz.transition 1968, 10, :o2, 14640937, 6
-
1
tz.transition 1969, 3, :o1, 14641735, 6
-
1
tz.transition 1969, 10, :o2, 14643121, 6
-
1
tz.transition 1970, 3, :o1, 5673600
-
1
tz.transition 1970, 10, :o2, 25632000
-
1
tz.transition 1971, 3, :o1, 37728000
-
1
tz.transition 1971, 10, :o2, 57686400
-
1
tz.transition 1972, 2, :o1, 67968000
-
1
tz.transition 1972, 10, :o2, 89136000
-
1
tz.transition 1973, 3, :o1, 100022400
-
1
tz.transition 1973, 10, :o2, 120585600
-
1
tz.transition 1974, 3, :o1, 131472000
-
1
tz.transition 1974, 10, :o2, 152035200
-
1
tz.transition 1975, 3, :o1, 162921600
-
1
tz.transition 1975, 10, :o2, 183484800
-
1
tz.transition 1976, 3, :o1, 194976000
-
1
tz.transition 1976, 10, :o2, 215539200
-
1
tz.transition 1977, 3, :o1, 226425600
-
1
tz.transition 1977, 10, :o2, 246988800
-
1
tz.transition 1978, 3, :o1, 257875200
-
1
tz.transition 1978, 10, :o2, 278438400
-
1
tz.transition 1979, 3, :o1, 289324800
-
1
tz.transition 1979, 10, :o2, 309888000
-
1
tz.transition 1980, 3, :o1, 320774400
-
1
tz.transition 1980, 10, :o2, 341337600
-
1
tz.transition 1981, 2, :o1, 352224000
-
1
tz.transition 1981, 10, :o2, 372787200
-
1
tz.transition 1982, 3, :o1, 386092800
-
1
tz.transition 1982, 10, :o2, 404841600
-
1
tz.transition 1983, 3, :o1, 417542400
-
1
tz.transition 1983, 10, :o2, 436291200
-
1
tz.transition 1984, 3, :o1, 447177600
-
1
tz.transition 1984, 10, :o2, 467740800
-
1
tz.transition 1985, 3, :o1, 478627200
-
1
tz.transition 1985, 10, :o2, 499190400
-
1
tz.transition 1986, 3, :o1, 510076800
-
1
tz.transition 1986, 10, :o2, 530035200
-
1
tz.transition 1987, 3, :o1, 542736000
-
1
tz.transition 1987, 10, :o2, 562089600
-
1
tz.transition 1988, 3, :o1, 574790400
-
1
tz.transition 1988, 10, :o2, 594144000
-
1
tz.transition 1989, 3, :o1, 606240000
-
1
tz.transition 1989, 10, :o2, 625593600
-
1
tz.transition 1990, 3, :o1, 637689600
-
1
tz.transition 1990, 10, :o2, 657043200
-
1
tz.transition 1991, 3, :o1, 670348800
-
1
tz.transition 1991, 10, :o2, 686678400
-
1
tz.transition 1992, 3, :o1, 701798400
-
1
tz.transition 1992, 10, :o2, 718128000
-
1
tz.transition 1993, 3, :o1, 733248000
-
1
tz.transition 1993, 10, :o2, 749577600
-
1
tz.transition 1994, 3, :o1, 764697600
-
1
tz.transition 1994, 10, :o2, 781027200
-
1
tz.transition 1995, 3, :o1, 796147200
-
1
tz.transition 1995, 9, :o2, 812476800
-
1
tz.transition 1996, 3, :o1, 828201600
-
1
tz.transition 1996, 10, :o2, 844531200
-
1
tz.transition 1997, 3, :o1, 859651200
-
1
tz.transition 1997, 10, :o2, 875980800
-
1
tz.transition 1998, 3, :o1, 891100800
-
1
tz.transition 1998, 10, :o2, 907430400
-
1
tz.transition 1999, 3, :o1, 922550400
-
1
tz.transition 1999, 10, :o2, 938880000
-
1
tz.transition 2000, 3, :o1, 954000000
-
1
tz.transition 2000, 8, :o2, 967305600
-
1
tz.transition 2001, 3, :o1, 985449600
-
1
tz.transition 2001, 10, :o2, 1002384000
-
1
tz.transition 2002, 3, :o1, 1017504000
-
1
tz.transition 2002, 10, :o2, 1033833600
-
1
tz.transition 2003, 3, :o1, 1048953600
-
1
tz.transition 2003, 10, :o2, 1065283200
-
1
tz.transition 2004, 3, :o1, 1080403200
-
1
tz.transition 2004, 10, :o2, 1096732800
-
1
tz.transition 2005, 3, :o1, 1111852800
-
1
tz.transition 2005, 10, :o2, 1128182400
-
1
tz.transition 2006, 4, :o1, 1143907200
-
1
tz.transition 2006, 9, :o2, 1159632000
-
1
tz.transition 2007, 3, :o1, 1174752000
-
1
tz.transition 2007, 10, :o2, 1191686400
-
1
tz.transition 2008, 4, :o1, 1207411200
-
1
tz.transition 2008, 10, :o2, 1223136000
-
1
tz.transition 2009, 4, :o1, 1238860800
-
1
tz.transition 2009, 10, :o2, 1254585600
-
1
tz.transition 2010, 4, :o1, 1270310400
-
1
tz.transition 2010, 10, :o2, 1286035200
-
1
tz.transition 2011, 4, :o1, 1301760000
-
1
tz.transition 2011, 10, :o2, 1317484800
-
1
tz.transition 2012, 3, :o1, 1333209600
-
1
tz.transition 2012, 10, :o2, 1349539200
-
1
tz.transition 2013, 4, :o1, 1365264000
-
1
tz.transition 2013, 10, :o2, 1380988800
-
1
tz.transition 2014, 4, :o1, 1396713600
-
1
tz.transition 2014, 10, :o2, 1412438400
-
1
tz.transition 2015, 4, :o1, 1428163200
-
1
tz.transition 2015, 10, :o2, 1443888000
-
1
tz.transition 2016, 4, :o1, 1459612800
-
1
tz.transition 2016, 10, :o2, 1475337600
-
1
tz.transition 2017, 4, :o1, 1491062400
-
1
tz.transition 2017, 9, :o2, 1506787200
-
1
tz.transition 2018, 3, :o1, 1522512000
-
1
tz.transition 2018, 10, :o2, 1538841600
-
1
tz.transition 2019, 4, :o1, 1554566400
-
1
tz.transition 2019, 10, :o2, 1570291200
-
1
tz.transition 2020, 4, :o1, 1586016000
-
1
tz.transition 2020, 10, :o2, 1601740800
-
1
tz.transition 2021, 4, :o1, 1617465600
-
1
tz.transition 2021, 10, :o2, 1633190400
-
1
tz.transition 2022, 4, :o1, 1648915200
-
1
tz.transition 2022, 10, :o2, 1664640000
-
1
tz.transition 2023, 4, :o1, 1680364800
-
1
tz.transition 2023, 9, :o2, 1696089600
-
1
tz.transition 2024, 4, :o1, 1712419200
-
1
tz.transition 2024, 10, :o2, 1728144000
-
1
tz.transition 2025, 4, :o1, 1743868800
-
1
tz.transition 2025, 10, :o2, 1759593600
-
1
tz.transition 2026, 4, :o1, 1775318400
-
1
tz.transition 2026, 10, :o2, 1791043200
-
1
tz.transition 2027, 4, :o1, 1806768000
-
1
tz.transition 2027, 10, :o2, 1822492800
-
1
tz.transition 2028, 4, :o1, 1838217600
-
1
tz.transition 2028, 9, :o2, 1853942400
-
1
tz.transition 2029, 3, :o1, 1869667200
-
1
tz.transition 2029, 10, :o2, 1885996800
-
1
tz.transition 2030, 4, :o1, 1901721600
-
1
tz.transition 2030, 10, :o2, 1917446400
-
1
tz.transition 2031, 4, :o1, 1933171200
-
1
tz.transition 2031, 10, :o2, 1948896000
-
1
tz.transition 2032, 4, :o1, 1964620800
-
1
tz.transition 2032, 10, :o2, 1980345600
-
1
tz.transition 2033, 4, :o1, 1996070400
-
1
tz.transition 2033, 10, :o2, 2011795200
-
1
tz.transition 2034, 4, :o1, 2027520000
-
1
tz.transition 2034, 9, :o2, 2043244800
-
1
tz.transition 2035, 3, :o1, 2058969600
-
1
tz.transition 2035, 10, :o2, 2075299200
-
1
tz.transition 2036, 4, :o1, 2091024000
-
1
tz.transition 2036, 10, :o2, 2106748800
-
1
tz.transition 2037, 4, :o1, 2122473600
-
1
tz.transition 2037, 10, :o2, 2138198400
-
1
tz.transition 2038, 4, :o1, 14793103, 6
-
1
tz.transition 2038, 10, :o2, 14794195, 6
-
1
tz.transition 2039, 4, :o1, 14795287, 6
-
1
tz.transition 2039, 10, :o2, 14796379, 6
-
1
tz.transition 2040, 3, :o1, 14797471, 6
-
1
tz.transition 2040, 10, :o2, 14798605, 6
-
1
tz.transition 2041, 4, :o1, 14799697, 6
-
1
tz.transition 2041, 10, :o2, 14800789, 6
-
1
tz.transition 2042, 4, :o1, 14801881, 6
-
1
tz.transition 2042, 10, :o2, 14802973, 6
-
1
tz.transition 2043, 4, :o1, 14804065, 6
-
1
tz.transition 2043, 10, :o2, 14805157, 6
-
1
tz.transition 2044, 4, :o1, 14806249, 6
-
1
tz.transition 2044, 10, :o2, 14807341, 6
-
1
tz.transition 2045, 4, :o1, 14808433, 6
-
1
tz.transition 2045, 9, :o2, 14809525, 6
-
1
tz.transition 2046, 3, :o1, 14810617, 6
-
1
tz.transition 2046, 10, :o2, 14811751, 6
-
1
tz.transition 2047, 4, :o1, 14812843, 6
-
1
tz.transition 2047, 10, :o2, 14813935, 6
-
1
tz.transition 2048, 4, :o1, 14815027, 6
-
1
tz.transition 2048, 10, :o2, 14816119, 6
-
1
tz.transition 2049, 4, :o1, 14817211, 6
-
1
tz.transition 2049, 10, :o2, 14818303, 6
-
1
tz.transition 2050, 4, :o1, 14819395, 6
-
end
-
end
-
end
-
end
-
end
-
1
module TZInfo
-
1
module Definitions
-
1
module Australia
-
1
module Melbourne
-
1
include TimezoneDefinition
-
-
1
timezone 'Australia/Melbourne' do |tz|
-
1
tz.offset :o0, 34792, 0, :LMT
-
1
tz.offset :o1, 36000, 0, :EST
-
1
tz.offset :o2, 36000, 3600, :EST
-
-
1
tz.transition 1895, 1, :o1, 26062831051, 10800
-
1
tz.transition 1916, 12, :o2, 3486569881, 1440
-
1
tz.transition 1917, 3, :o1, 19370497, 8
-
1
tz.transition 1941, 12, :o2, 14582161, 6
-
1
tz.transition 1942, 3, :o1, 19443577, 8
-
1
tz.transition 1942, 9, :o2, 14583775, 6
-
1
tz.transition 1943, 3, :o1, 19446489, 8
-
1
tz.transition 1943, 10, :o2, 14586001, 6
-
1
tz.transition 1944, 3, :o1, 19449401, 8
-
1
tz.transition 1971, 10, :o2, 57686400
-
1
tz.transition 1972, 2, :o1, 67968000
-
1
tz.transition 1972, 10, :o2, 89136000
-
1
tz.transition 1973, 3, :o1, 100022400
-
1
tz.transition 1973, 10, :o2, 120585600
-
1
tz.transition 1974, 3, :o1, 131472000
-
1
tz.transition 1974, 10, :o2, 152035200
-
1
tz.transition 1975, 3, :o1, 162921600
-
1
tz.transition 1975, 10, :o2, 183484800
-
1
tz.transition 1976, 3, :o1, 194976000
-
1
tz.transition 1976, 10, :o2, 215539200
-
1
tz.transition 1977, 3, :o1, 226425600
-
1
tz.transition 1977, 10, :o2, 246988800
-
1
tz.transition 1978, 3, :o1, 257875200
-
1
tz.transition 1978, 10, :o2, 278438400
-
1
tz.transition 1979, 3, :o1, 289324800
-
1
tz.transition 1979, 10, :o2, 309888000
-
1
tz.transition 1980, 3, :o1, 320774400
-
1
tz.transition 1980, 10, :o2, 341337600
-
1
tz.transition 1981, 2, :o1, 352224000
-
1
tz.transition 1981, 10, :o2, 372787200
-
1
tz.transition 1982, 3, :o1, 384278400
-
1
tz.transition 1982, 10, :o2, 404841600
-
1
tz.transition 1983, 3, :o1, 415728000
-
1
tz.transition 1983, 10, :o2, 436291200
-
1
tz.transition 1984, 3, :o1, 447177600
-
1
tz.transition 1984, 10, :o2, 467740800
-
1
tz.transition 1985, 3, :o1, 478627200
-
1
tz.transition 1985, 10, :o2, 499190400
-
1
tz.transition 1986, 3, :o1, 511286400
-
1
tz.transition 1986, 10, :o2, 530035200
-
1
tz.transition 1987, 3, :o1, 542736000
-
1
tz.transition 1987, 10, :o2, 561484800
-
1
tz.transition 1988, 3, :o1, 574790400
-
1
tz.transition 1988, 10, :o2, 594144000
-
1
tz.transition 1989, 3, :o1, 606240000
-
1
tz.transition 1989, 10, :o2, 625593600
-
1
tz.transition 1990, 3, :o1, 637689600
-
1
tz.transition 1990, 10, :o2, 657043200
-
1
tz.transition 1991, 3, :o1, 667929600
-
1
tz.transition 1991, 10, :o2, 688492800
-
1
tz.transition 1992, 2, :o1, 699379200
-
1
tz.transition 1992, 10, :o2, 719942400
-
1
tz.transition 1993, 3, :o1, 731433600
-
1
tz.transition 1993, 10, :o2, 751996800
-
1
tz.transition 1994, 3, :o1, 762883200
-
1
tz.transition 1994, 10, :o2, 783446400
-
1
tz.transition 1995, 3, :o1, 796147200
-
1
tz.transition 1995, 10, :o2, 814896000
-
1
tz.transition 1996, 3, :o1, 828201600
-
1
tz.transition 1996, 10, :o2, 846345600
-
1
tz.transition 1997, 3, :o1, 859651200
-
1
tz.transition 1997, 10, :o2, 877795200
-
1
tz.transition 1998, 3, :o1, 891100800
-
1
tz.transition 1998, 10, :o2, 909244800
-
1
tz.transition 1999, 3, :o1, 922550400
-
1
tz.transition 1999, 10, :o2, 941299200
-
1
tz.transition 2000, 3, :o1, 954000000
-
1
tz.transition 2000, 8, :o2, 967305600
-
1
tz.transition 2001, 3, :o1, 985449600
-
1
tz.transition 2001, 10, :o2, 1004198400
-
1
tz.transition 2002, 3, :o1, 1017504000
-
1
tz.transition 2002, 10, :o2, 1035648000
-
1
tz.transition 2003, 3, :o1, 1048953600
-
1
tz.transition 2003, 10, :o2, 1067097600
-
1
tz.transition 2004, 3, :o1, 1080403200
-
1
tz.transition 2004, 10, :o2, 1099152000
-
1
tz.transition 2005, 3, :o1, 1111852800
-
1
tz.transition 2005, 10, :o2, 1130601600
-
1
tz.transition 2006, 4, :o1, 1143907200
-
1
tz.transition 2006, 10, :o2, 1162051200
-
1
tz.transition 2007, 3, :o1, 1174752000
-
1
tz.transition 2007, 10, :o2, 1193500800
-
1
tz.transition 2008, 4, :o1, 1207411200
-
1
tz.transition 2008, 10, :o2, 1223136000
-
1
tz.transition 2009, 4, :o1, 1238860800
-
1
tz.transition 2009, 10, :o2, 1254585600
-
1
tz.transition 2010, 4, :o1, 1270310400
-
1
tz.transition 2010, 10, :o2, 1286035200
-
1
tz.transition 2011, 4, :o1, 1301760000
-
1
tz.transition 2011, 10, :o2, 1317484800
-
1
tz.transition 2012, 3, :o1, 1333209600
-
1
tz.transition 2012, 10, :o2, 1349539200
-
1
tz.transition 2013, 4, :o1, 1365264000
-
1
tz.transition 2013, 10, :o2, 1380988800
-
1
tz.transition 2014, 4, :o1, 1396713600
-
1
tz.transition 2014, 10, :o2, 1412438400
-
1
tz.transition 2015, 4, :o1, 1428163200
-
1
tz.transition 2015, 10, :o2, 1443888000
-
1
tz.transition 2016, 4, :o1, 1459612800
-
1
tz.transition 2016, 10, :o2, 1475337600
-
1
tz.transition 2017, 4, :o1, 1491062400
-
1
tz.transition 2017, 9, :o2, 1506787200
-
1
tz.transition 2018, 3, :o1, 1522512000
-
1
tz.transition 2018, 10, :o2, 1538841600
-
1
tz.transition 2019, 4, :o1, 1554566400
-
1
tz.transition 2019, 10, :o2, 1570291200
-
1
tz.transition 2020, 4, :o1, 1586016000
-
1
tz.transition 2020, 10, :o2, 1601740800
-
1
tz.transition 2021, 4, :o1, 1617465600
-
1
tz.transition 2021, 10, :o2, 1633190400
-
1
tz.transition 2022, 4, :o1, 1648915200
-
1
tz.transition 2022, 10, :o2, 1664640000
-
1
tz.transition 2023, 4, :o1, 1680364800
-
1
tz.transition 2023, 9, :o2, 1696089600
-
1
tz.transition 2024, 4, :o1, 1712419200
-
1
tz.transition 2024, 10, :o2, 1728144000
-
1
tz.transition 2025, 4, :o1, 1743868800
-
1
tz.transition 2025, 10, :o2, 1759593600
-
1
tz.transition 2026, 4, :o1, 1775318400
-
1
tz.transition 2026, 10, :o2, 1791043200
-
1
tz.transition 2027, 4, :o1, 1806768000
-
1
tz.transition 2027, 10, :o2, 1822492800
-
1
tz.transition 2028, 4, :o1, 1838217600
-
1
tz.transition 2028, 9, :o2, 1853942400
-
1
tz.transition 2029, 3, :o1, 1869667200
-
1
tz.transition 2029, 10, :o2, 1885996800
-
1
tz.transition 2030, 4, :o1, 1901721600
-
1
tz.transition 2030, 10, :o2, 1917446400
-
1
tz.transition 2031, 4, :o1, 1933171200
-
1
tz.transition 2031, 10, :o2, 1948896000
-
1
tz.transition 2032, 4, :o1, 1964620800
-
1
tz.transition 2032, 10, :o2, 1980345600
-
1
tz.transition 2033, 4, :o1, 1996070400
-
1
tz.transition 2033, 10, :o2, 2011795200
-
1
tz.transition 2034, 4, :o1, 2027520000
-
1
tz.transition 2034, 9, :o2, 2043244800
-
1
tz.transition 2035, 3, :o1, 2058969600
-
1
tz.transition 2035, 10, :o2, 2075299200
-
1
tz.transition 2036, 4, :o1, 2091024000
-
1
tz.transition 2036, 10, :o2, 2106748800
-
1
tz.transition 2037, 4, :o1, 2122473600
-
1
tz.transition 2037, 10, :o2, 2138198400
-
1
tz.transition 2038, 4, :o1, 14793103, 6
-
1
tz.transition 2038, 10, :o2, 14794195, 6
-
1
tz.transition 2039, 4, :o1, 14795287, 6
-
1
tz.transition 2039, 10, :o2, 14796379, 6
-
1
tz.transition 2040, 3, :o1, 14797471, 6
-
1
tz.transition 2040, 10, :o2, 14798605, 6
-
1
tz.transition 2041, 4, :o1, 14799697, 6
-
1
tz.transition 2041, 10, :o2, 14800789, 6
-
1
tz.transition 2042, 4, :o1, 14801881, 6
-
1
tz.transition 2042, 10, :o2, 14802973, 6
-
1
tz.transition 2043, 4, :o1, 14804065, 6
-
1
tz.transition 2043, 10, :o2, 14805157, 6
-
1
tz.transition 2044, 4, :o1, 14806249, 6
-
1
tz.transition 2044, 10, :o2, 14807341, 6
-
1
tz.transition 2045, 4, :o1, 14808433, 6
-
1
tz.transition 2045, 9, :o2, 14809525, 6
-
1
tz.transition 2046, 3, :o1, 14810617, 6
-
1
tz.transition 2046, 10, :o2, 14811751, 6
-
1
tz.transition 2047, 4, :o1, 14812843, 6
-
1
tz.transition 2047, 10, :o2, 14813935, 6
-
1
tz.transition 2048, 4, :o1, 14815027, 6
-
1
tz.transition 2048, 10, :o2, 14816119, 6
-
1
tz.transition 2049, 4, :o1, 14817211, 6
-
1
tz.transition 2049, 10, :o2, 14818303, 6
-
1
tz.transition 2050, 4, :o1, 14819395, 6
-
end
-
end
-
end
-
end
-
end
-
1
module TZInfo
-
1
module Definitions
-
1
module Australia
-
1
module Perth
-
1
include TimezoneDefinition
-
-
1
timezone 'Australia/Perth' do |tz|
-
1
tz.offset :o0, 27804, 0, :LMT
-
1
tz.offset :o1, 28800, 0, :WST
-
1
tz.offset :o2, 28800, 3600, :WST
-
-
1
tz.transition 1895, 11, :o1, 17377402883, 7200
-
1
tz.transition 1916, 12, :o2, 3486570001, 1440
-
1
tz.transition 1917, 3, :o1, 58111493, 24
-
1
tz.transition 1941, 12, :o2, 9721441, 4
-
1
tz.transition 1942, 3, :o1, 58330733, 24
-
1
tz.transition 1942, 9, :o2, 9722517, 4
-
1
tz.transition 1943, 3, :o1, 58339469, 24
-
1
tz.transition 1974, 10, :o2, 152042400
-
1
tz.transition 1975, 3, :o1, 162928800
-
1
tz.transition 1983, 10, :o2, 436298400
-
1
tz.transition 1984, 3, :o1, 447184800
-
1
tz.transition 1991, 11, :o2, 690314400
-
1
tz.transition 1992, 2, :o1, 699386400
-
1
tz.transition 2006, 12, :o2, 1165082400
-
1
tz.transition 2007, 3, :o1, 1174759200
-
1
tz.transition 2007, 10, :o2, 1193508000
-
1
tz.transition 2008, 3, :o1, 1206813600
-
1
tz.transition 2008, 10, :o2, 1224957600
-
1
tz.transition 2009, 3, :o1, 1238263200
-
end
-
end
-
end
-
end
-
end
-
1
module TZInfo
-
1
module Definitions
-
1
module Australia
-
1
module Sydney
-
1
include TimezoneDefinition
-
-
1
timezone 'Australia/Sydney' do |tz|
-
1
tz.offset :o0, 36292, 0, :LMT
-
1
tz.offset :o1, 36000, 0, :EST
-
1
tz.offset :o2, 36000, 3600, :EST
-
-
1
tz.transition 1895, 1, :o1, 52125661727, 21600
-
1
tz.transition 1916, 12, :o2, 3486569881, 1440
-
1
tz.transition 1917, 3, :o1, 19370497, 8
-
1
tz.transition 1941, 12, :o2, 14582161, 6
-
1
tz.transition 1942, 3, :o1, 19443577, 8
-
1
tz.transition 1942, 9, :o2, 14583775, 6
-
1
tz.transition 1943, 3, :o1, 19446489, 8
-
1
tz.transition 1943, 10, :o2, 14586001, 6
-
1
tz.transition 1944, 3, :o1, 19449401, 8
-
1
tz.transition 1971, 10, :o2, 57686400
-
1
tz.transition 1972, 2, :o1, 67968000
-
1
tz.transition 1972, 10, :o2, 89136000
-
1
tz.transition 1973, 3, :o1, 100022400
-
1
tz.transition 1973, 10, :o2, 120585600
-
1
tz.transition 1974, 3, :o1, 131472000
-
1
tz.transition 1974, 10, :o2, 152035200
-
1
tz.transition 1975, 3, :o1, 162921600
-
1
tz.transition 1975, 10, :o2, 183484800
-
1
tz.transition 1976, 3, :o1, 194976000
-
1
tz.transition 1976, 10, :o2, 215539200
-
1
tz.transition 1977, 3, :o1, 226425600
-
1
tz.transition 1977, 10, :o2, 246988800
-
1
tz.transition 1978, 3, :o1, 257875200
-
1
tz.transition 1978, 10, :o2, 278438400
-
1
tz.transition 1979, 3, :o1, 289324800
-
1
tz.transition 1979, 10, :o2, 309888000
-
1
tz.transition 1980, 3, :o1, 320774400
-
1
tz.transition 1980, 10, :o2, 341337600
-
1
tz.transition 1981, 2, :o1, 352224000
-
1
tz.transition 1981, 10, :o2, 372787200
-
1
tz.transition 1982, 4, :o1, 386697600
-
1
tz.transition 1982, 10, :o2, 404841600
-
1
tz.transition 1983, 3, :o1, 415728000
-
1
tz.transition 1983, 10, :o2, 436291200
-
1
tz.transition 1984, 3, :o1, 447177600
-
1
tz.transition 1984, 10, :o2, 467740800
-
1
tz.transition 1985, 3, :o1, 478627200
-
1
tz.transition 1985, 10, :o2, 499190400
-
1
tz.transition 1986, 3, :o1, 511286400
-
1
tz.transition 1986, 10, :o2, 530035200
-
1
tz.transition 1987, 3, :o1, 542736000
-
1
tz.transition 1987, 10, :o2, 562089600
-
1
tz.transition 1988, 3, :o1, 574790400
-
1
tz.transition 1988, 10, :o2, 594144000
-
1
tz.transition 1989, 3, :o1, 606240000
-
1
tz.transition 1989, 10, :o2, 625593600
-
1
tz.transition 1990, 3, :o1, 636480000
-
1
tz.transition 1990, 10, :o2, 657043200
-
1
tz.transition 1991, 3, :o1, 667929600
-
1
tz.transition 1991, 10, :o2, 688492800
-
1
tz.transition 1992, 2, :o1, 699379200
-
1
tz.transition 1992, 10, :o2, 719942400
-
1
tz.transition 1993, 3, :o1, 731433600
-
1
tz.transition 1993, 10, :o2, 751996800
-
1
tz.transition 1994, 3, :o1, 762883200
-
1
tz.transition 1994, 10, :o2, 783446400
-
1
tz.transition 1995, 3, :o1, 794332800
-
1
tz.transition 1995, 10, :o2, 814896000
-
1
tz.transition 1996, 3, :o1, 828201600
-
1
tz.transition 1996, 10, :o2, 846345600
-
1
tz.transition 1997, 3, :o1, 859651200
-
1
tz.transition 1997, 10, :o2, 877795200
-
1
tz.transition 1998, 3, :o1, 891100800
-
1
tz.transition 1998, 10, :o2, 909244800
-
1
tz.transition 1999, 3, :o1, 922550400
-
1
tz.transition 1999, 10, :o2, 941299200
-
1
tz.transition 2000, 3, :o1, 954000000
-
1
tz.transition 2000, 8, :o2, 967305600
-
1
tz.transition 2001, 3, :o1, 985449600
-
1
tz.transition 2001, 10, :o2, 1004198400
-
1
tz.transition 2002, 3, :o1, 1017504000
-
1
tz.transition 2002, 10, :o2, 1035648000
-
1
tz.transition 2003, 3, :o1, 1048953600
-
1
tz.transition 2003, 10, :o2, 1067097600
-
1
tz.transition 2004, 3, :o1, 1080403200
-
1
tz.transition 2004, 10, :o2, 1099152000
-
1
tz.transition 2005, 3, :o1, 1111852800
-
1
tz.transition 2005, 10, :o2, 1130601600
-
1
tz.transition 2006, 4, :o1, 1143907200
-
1
tz.transition 2006, 10, :o2, 1162051200
-
1
tz.transition 2007, 3, :o1, 1174752000
-
1
tz.transition 2007, 10, :o2, 1193500800
-
1
tz.transition 2008, 4, :o1, 1207411200
-
1
tz.transition 2008, 10, :o2, 1223136000
-
1
tz.transition 2009, 4, :o1, 1238860800
-
1
tz.transition 2009, 10, :o2, 1254585600
-
1
tz.transition 2010, 4, :o1, 1270310400
-
1
tz.transition 2010, 10, :o2, 1286035200
-
1
tz.transition 2011, 4, :o1, 1301760000
-
1
tz.transition 2011, 10, :o2, 1317484800
-
1
tz.transition 2012, 3, :o1, 1333209600
-
1
tz.transition 2012, 10, :o2, 1349539200
-
1
tz.transition 2013, 4, :o1, 1365264000
-
1
tz.transition 2013, 10, :o2, 1380988800
-
1
tz.transition 2014, 4, :o1, 1396713600
-
1
tz.transition 2014, 10, :o2, 1412438400
-
1
tz.transition 2015, 4, :o1, 1428163200
-
1
tz.transition 2015, 10, :o2, 1443888000
-
1
tz.transition 2016, 4, :o1, 1459612800
-
1
tz.transition 2016, 10, :o2, 1475337600
-
1
tz.transition 2017, 4, :o1, 1491062400
-
1
tz.transition 2017, 9, :o2, 1506787200
-
1
tz.transition 2018, 3, :o1, 1522512000
-
1
tz.transition 2018, 10, :o2, 1538841600
-
1
tz.transition 2019, 4, :o1, 1554566400
-
1
tz.transition 2019, 10, :o2, 1570291200
-
1
tz.transition 2020, 4, :o1, 1586016000
-
1
tz.transition 2020, 10, :o2, 1601740800
-
1
tz.transition 2021, 4, :o1, 1617465600
-
1
tz.transition 2021, 10, :o2, 1633190400
-
1
tz.transition 2022, 4, :o1, 1648915200
-
1
tz.transition 2022, 10, :o2, 1664640000
-
1
tz.transition 2023, 4, :o1, 1680364800
-
1
tz.transition 2023, 9, :o2, 1696089600
-
1
tz.transition 2024, 4, :o1, 1712419200
-
1
tz.transition 2024, 10, :o2, 1728144000
-
1
tz.transition 2025, 4, :o1, 1743868800
-
1
tz.transition 2025, 10, :o2, 1759593600
-
1
tz.transition 2026, 4, :o1, 1775318400
-
1
tz.transition 2026, 10, :o2, 1791043200
-
1
tz.transition 2027, 4, :o1, 1806768000
-
1
tz.transition 2027, 10, :o2, 1822492800
-
1
tz.transition 2028, 4, :o1, 1838217600
-
1
tz.transition 2028, 9, :o2, 1853942400
-
1
tz.transition 2029, 3, :o1, 1869667200
-
1
tz.transition 2029, 10, :o2, 1885996800
-
1
tz.transition 2030, 4, :o1, 1901721600
-
1
tz.transition 2030, 10, :o2, 1917446400
-
1
tz.transition 2031, 4, :o1, 1933171200
-
1
tz.transition 2031, 10, :o2, 1948896000
-
1
tz.transition 2032, 4, :o1, 1964620800
-
1
tz.transition 2032, 10, :o2, 1980345600
-
1
tz.transition 2033, 4, :o1, 1996070400
-
1
tz.transition 2033, 10, :o2, 2011795200
-
1
tz.transition 2034, 4, :o1, 2027520000
-
1
tz.transition 2034, 9, :o2, 2043244800
-
1
tz.transition 2035, 3, :o1, 2058969600
-
1
tz.transition 2035, 10, :o2, 2075299200
-
1
tz.transition 2036, 4, :o1, 2091024000
-
1
tz.transition 2036, 10, :o2, 2106748800
-
1
tz.transition 2037, 4, :o1, 2122473600
-
1
tz.transition 2037, 10, :o2, 2138198400
-
1
tz.transition 2038, 4, :o1, 14793103, 6
-
1
tz.transition 2038, 10, :o2, 14794195, 6
-
1
tz.transition 2039, 4, :o1, 14795287, 6
-
1
tz.transition 2039, 10, :o2, 14796379, 6
-
1
tz.transition 2040, 3, :o1, 14797471, 6
-
1
tz.transition 2040, 10, :o2, 14798605, 6
-
1
tz.transition 2041, 4, :o1, 14799697, 6
-
1
tz.transition 2041, 10, :o2, 14800789, 6
-
1
tz.transition 2042, 4, :o1, 14801881, 6
-
1
tz.transition 2042, 10, :o2, 14802973, 6
-
1
tz.transition 2043, 4, :o1, 14804065, 6
-
1
tz.transition 2043, 10, :o2, 14805157, 6
-
1
tz.transition 2044, 4, :o1, 14806249, 6
-
1
tz.transition 2044, 10, :o2, 14807341, 6
-
1
tz.transition 2045, 4, :o1, 14808433, 6
-
1
tz.transition 2045, 9, :o2, 14809525, 6
-
1
tz.transition 2046, 3, :o1, 14810617, 6
-
1
tz.transition 2046, 10, :o2, 14811751, 6
-
1
tz.transition 2047, 4, :o1, 14812843, 6
-
1
tz.transition 2047, 10, :o2, 14813935, 6
-
1
tz.transition 2048, 4, :o1, 14815027, 6
-
1
tz.transition 2048, 10, :o2, 14816119, 6
-
1
tz.transition 2049, 4, :o1, 14817211, 6
-
1
tz.transition 2049, 10, :o2, 14818303, 6
-
1
tz.transition 2050, 4, :o1, 14819395, 6
-
end
-
end
-
end
-
end
-
end
-
1
module TZInfo
-
1
module Definitions
-
1
module EST
-
1
include TimezoneDefinition
-
-
1
timezone 'EST' do |tz|
-
1
tz.offset :o0, -18000, 0, :EST
-
-
end
-
end
-
end
-
end
-
1
module TZInfo
-
1
module Definitions
-
1
module Etc
-
1
module UTC
-
1
include TimezoneDefinition
-
-
1
timezone 'Etc/UTC' do |tz|
-
1
tz.offset :o0, 0, 0, :UTC
-
-
end
-
end
-
end
-
end
-
end
-
1
module TZInfo
-
1
module Definitions
-
1
module Europe
-
1
module Amsterdam
-
1
include TimezoneDefinition
-
-
1
timezone 'Europe/Amsterdam' do |tz|
-
1
tz.offset :o0, 1172, 0, :LMT
-
1
tz.offset :o1, 1172, 0, :AMT
-
1
tz.offset :o2, 1172, 3600, :NST
-
1
tz.offset :o3, 1200, 3600, :NEST
-
1
tz.offset :o4, 1200, 0, :NET
-
1
tz.offset :o5, 3600, 3600, :CEST
-
1
tz.offset :o6, 3600, 0, :CET
-
-
1
tz.transition 1834, 12, :o1, 51651636907, 21600
-
1
tz.transition 1916, 4, :o2, 52293264907, 21600
-
1
tz.transition 1916, 9, :o1, 52296568807, 21600
-
1
tz.transition 1917, 4, :o2, 52300826707, 21600
-
1
tz.transition 1917, 9, :o1, 52304153107, 21600
-
1
tz.transition 1918, 4, :o2, 52308386707, 21600
-
1
tz.transition 1918, 9, :o1, 52312317907, 21600
-
1
tz.transition 1919, 4, :o2, 52316400307, 21600
-
1
tz.transition 1919, 9, :o1, 52320180307, 21600
-
1
tz.transition 1920, 4, :o2, 52324262707, 21600
-
1
tz.transition 1920, 9, :o1, 52328042707, 21600
-
1
tz.transition 1921, 4, :o2, 52332125107, 21600
-
1
tz.transition 1921, 9, :o1, 52335905107, 21600
-
1
tz.transition 1922, 3, :o2, 52339814707, 21600
-
1
tz.transition 1922, 10, :o1, 52344048307, 21600
-
1
tz.transition 1923, 6, :o2, 52349145907, 21600
-
1
tz.transition 1923, 10, :o1, 52351910707, 21600
-
1
tz.transition 1924, 3, :o2, 52355690707, 21600
-
1
tz.transition 1924, 10, :o1, 52359773107, 21600
-
1
tz.transition 1925, 6, :o2, 52365021907, 21600
-
1
tz.transition 1925, 10, :o1, 52367635507, 21600
-
1
tz.transition 1926, 5, :o2, 52372452307, 21600
-
1
tz.transition 1926, 10, :o1, 52375497907, 21600
-
1
tz.transition 1927, 5, :o2, 52380336307, 21600
-
1
tz.transition 1927, 10, :o1, 52383360307, 21600
-
1
tz.transition 1928, 5, :o2, 52388241907, 21600
-
1
tz.transition 1928, 10, :o1, 52391373907, 21600
-
1
tz.transition 1929, 5, :o2, 52396125907, 21600
-
1
tz.transition 1929, 10, :o1, 52399236307, 21600
-
1
tz.transition 1930, 5, :o2, 52404009907, 21600
-
1
tz.transition 1930, 10, :o1, 52407098707, 21600
-
1
tz.transition 1931, 5, :o2, 52411893907, 21600
-
1
tz.transition 1931, 10, :o1, 52414961107, 21600
-
1
tz.transition 1932, 5, :o2, 52419950707, 21600
-
1
tz.transition 1932, 10, :o1, 52422823507, 21600
-
1
tz.transition 1933, 5, :o2, 52427683507, 21600
-
1
tz.transition 1933, 10, :o1, 52430837107, 21600
-
1
tz.transition 1934, 5, :o2, 52435567507, 21600
-
1
tz.transition 1934, 10, :o1, 52438699507, 21600
-
1
tz.transition 1935, 5, :o2, 52443451507, 21600
-
1
tz.transition 1935, 10, :o1, 52446561907, 21600
-
1
tz.transition 1936, 5, :o2, 52451357107, 21600
-
1
tz.transition 1936, 10, :o1, 52454424307, 21600
-
1
tz.transition 1937, 5, :o2, 52459392307, 21600
-
1
tz.transition 1937, 6, :o3, 52460253607, 21600
-
1
tz.transition 1937, 10, :o4, 174874289, 72
-
1
tz.transition 1938, 5, :o3, 174890417, 72
-
1
tz.transition 1938, 10, :o4, 174900497, 72
-
1
tz.transition 1939, 5, :o3, 174916697, 72
-
1
tz.transition 1939, 10, :o4, 174927209, 72
-
1
tz.transition 1940, 5, :o5, 174943115, 72
-
1
tz.transition 1942, 11, :o6, 58335973, 24
-
1
tz.transition 1943, 3, :o5, 58339501, 24
-
1
tz.transition 1943, 10, :o6, 58344037, 24
-
1
tz.transition 1944, 4, :o5, 58348405, 24
-
1
tz.transition 1944, 10, :o6, 58352773, 24
-
1
tz.transition 1945, 4, :o5, 58357141, 24
-
1
tz.transition 1945, 9, :o6, 58361149, 24
-
1
tz.transition 1977, 4, :o5, 228877200
-
1
tz.transition 1977, 9, :o6, 243997200
-
1
tz.transition 1978, 4, :o5, 260326800
-
1
tz.transition 1978, 10, :o6, 276051600
-
1
tz.transition 1979, 4, :o5, 291776400
-
1
tz.transition 1979, 9, :o6, 307501200
-
1
tz.transition 1980, 4, :o5, 323830800
-
1
tz.transition 1980, 9, :o6, 338950800
-
1
tz.transition 1981, 3, :o5, 354675600
-
1
tz.transition 1981, 9, :o6, 370400400
-
1
tz.transition 1982, 3, :o5, 386125200
-
1
tz.transition 1982, 9, :o6, 401850000
-
1
tz.transition 1983, 3, :o5, 417574800
-
1
tz.transition 1983, 9, :o6, 433299600
-
1
tz.transition 1984, 3, :o5, 449024400
-
1
tz.transition 1984, 9, :o6, 465354000
-
1
tz.transition 1985, 3, :o5, 481078800
-
1
tz.transition 1985, 9, :o6, 496803600
-
1
tz.transition 1986, 3, :o5, 512528400
-
1
tz.transition 1986, 9, :o6, 528253200
-
1
tz.transition 1987, 3, :o5, 543978000
-
1
tz.transition 1987, 9, :o6, 559702800
-
1
tz.transition 1988, 3, :o5, 575427600
-
1
tz.transition 1988, 9, :o6, 591152400
-
1
tz.transition 1989, 3, :o5, 606877200
-
1
tz.transition 1989, 9, :o6, 622602000
-
1
tz.transition 1990, 3, :o5, 638326800
-
1
tz.transition 1990, 9, :o6, 654656400
-
1
tz.transition 1991, 3, :o5, 670381200
-
1
tz.transition 1991, 9, :o6, 686106000
-
1
tz.transition 1992, 3, :o5, 701830800
-
1
tz.transition 1992, 9, :o6, 717555600
-
1
tz.transition 1993, 3, :o5, 733280400
-
1
tz.transition 1993, 9, :o6, 749005200
-
1
tz.transition 1994, 3, :o5, 764730000
-
1
tz.transition 1994, 9, :o6, 780454800
-
1
tz.transition 1995, 3, :o5, 796179600
-
1
tz.transition 1995, 9, :o6, 811904400
-
1
tz.transition 1996, 3, :o5, 828234000
-
1
tz.transition 1996, 10, :o6, 846378000
-
1
tz.transition 1997, 3, :o5, 859683600
-
1
tz.transition 1997, 10, :o6, 877827600
-
1
tz.transition 1998, 3, :o5, 891133200
-
1
tz.transition 1998, 10, :o6, 909277200
-
1
tz.transition 1999, 3, :o5, 922582800
-
1
tz.transition 1999, 10, :o6, 941331600
-
1
tz.transition 2000, 3, :o5, 954032400
-
1
tz.transition 2000, 10, :o6, 972781200
-
1
tz.transition 2001, 3, :o5, 985482000
-
1
tz.transition 2001, 10, :o6, 1004230800
-
1
tz.transition 2002, 3, :o5, 1017536400
-
1
tz.transition 2002, 10, :o6, 1035680400
-
1
tz.transition 2003, 3, :o5, 1048986000
-
1
tz.transition 2003, 10, :o6, 1067130000
-
1
tz.transition 2004, 3, :o5, 1080435600
-
1
tz.transition 2004, 10, :o6, 1099184400
-
1
tz.transition 2005, 3, :o5, 1111885200
-
1
tz.transition 2005, 10, :o6, 1130634000
-
1
tz.transition 2006, 3, :o5, 1143334800
-
1
tz.transition 2006, 10, :o6, 1162083600
-
1
tz.transition 2007, 3, :o5, 1174784400
-
1
tz.transition 2007, 10, :o6, 1193533200
-
1
tz.transition 2008, 3, :o5, 1206838800
-
1
tz.transition 2008, 10, :o6, 1224982800
-
1
tz.transition 2009, 3, :o5, 1238288400
-
1
tz.transition 2009, 10, :o6, 1256432400
-
1
tz.transition 2010, 3, :o5, 1269738000
-
1
tz.transition 2010, 10, :o6, 1288486800
-
1
tz.transition 2011, 3, :o5, 1301187600
-
1
tz.transition 2011, 10, :o6, 1319936400
-
1
tz.transition 2012, 3, :o5, 1332637200
-
1
tz.transition 2012, 10, :o6, 1351386000
-
1
tz.transition 2013, 3, :o5, 1364691600
-
1
tz.transition 2013, 10, :o6, 1382835600
-
1
tz.transition 2014, 3, :o5, 1396141200
-
1
tz.transition 2014, 10, :o6, 1414285200
-
1
tz.transition 2015, 3, :o5, 1427590800
-
1
tz.transition 2015, 10, :o6, 1445734800
-
1
tz.transition 2016, 3, :o5, 1459040400
-
1
tz.transition 2016, 10, :o6, 1477789200
-
1
tz.transition 2017, 3, :o5, 1490490000
-
1
tz.transition 2017, 10, :o6, 1509238800
-
1
tz.transition 2018, 3, :o5, 1521939600
-
1
tz.transition 2018, 10, :o6, 1540688400
-
1
tz.transition 2019, 3, :o5, 1553994000
-
1
tz.transition 2019, 10, :o6, 1572138000
-
1
tz.transition 2020, 3, :o5, 1585443600
-
1
tz.transition 2020, 10, :o6, 1603587600
-
1
tz.transition 2021, 3, :o5, 1616893200
-
1
tz.transition 2021, 10, :o6, 1635642000
-
1
tz.transition 2022, 3, :o5, 1648342800
-
1
tz.transition 2022, 10, :o6, 1667091600
-
1
tz.transition 2023, 3, :o5, 1679792400
-
1
tz.transition 2023, 10, :o6, 1698541200
-
1
tz.transition 2024, 3, :o5, 1711846800
-
1
tz.transition 2024, 10, :o6, 1729990800
-
1
tz.transition 2025, 3, :o5, 1743296400
-
1
tz.transition 2025, 10, :o6, 1761440400
-
1
tz.transition 2026, 3, :o5, 1774746000
-
1
tz.transition 2026, 10, :o6, 1792890000
-
1
tz.transition 2027, 3, :o5, 1806195600
-
1
tz.transition 2027, 10, :o6, 1824944400
-
1
tz.transition 2028, 3, :o5, 1837645200
-
1
tz.transition 2028, 10, :o6, 1856394000
-
1
tz.transition 2029, 3, :o5, 1869094800
-
1
tz.transition 2029, 10, :o6, 1887843600
-
1
tz.transition 2030, 3, :o5, 1901149200
-
1
tz.transition 2030, 10, :o6, 1919293200
-
1
tz.transition 2031, 3, :o5, 1932598800
-
1
tz.transition 2031, 10, :o6, 1950742800
-
1
tz.transition 2032, 3, :o5, 1964048400
-
1
tz.transition 2032, 10, :o6, 1982797200
-
1
tz.transition 2033, 3, :o5, 1995498000
-
1
tz.transition 2033, 10, :o6, 2014246800
-
1
tz.transition 2034, 3, :o5, 2026947600
-
1
tz.transition 2034, 10, :o6, 2045696400
-
1
tz.transition 2035, 3, :o5, 2058397200
-
1
tz.transition 2035, 10, :o6, 2077146000
-
1
tz.transition 2036, 3, :o5, 2090451600
-
1
tz.transition 2036, 10, :o6, 2108595600
-
1
tz.transition 2037, 3, :o5, 2121901200
-
1
tz.transition 2037, 10, :o6, 2140045200
-
1
tz.transition 2038, 3, :o5, 59172253, 24
-
1
tz.transition 2038, 10, :o6, 59177461, 24
-
1
tz.transition 2039, 3, :o5, 59180989, 24
-
1
tz.transition 2039, 10, :o6, 59186197, 24
-
1
tz.transition 2040, 3, :o5, 59189725, 24
-
1
tz.transition 2040, 10, :o6, 59194933, 24
-
1
tz.transition 2041, 3, :o5, 59198629, 24
-
1
tz.transition 2041, 10, :o6, 59203669, 24
-
1
tz.transition 2042, 3, :o5, 59207365, 24
-
1
tz.transition 2042, 10, :o6, 59212405, 24
-
1
tz.transition 2043, 3, :o5, 59216101, 24
-
1
tz.transition 2043, 10, :o6, 59221141, 24
-
1
tz.transition 2044, 3, :o5, 59224837, 24
-
1
tz.transition 2044, 10, :o6, 59230045, 24
-
1
tz.transition 2045, 3, :o5, 59233573, 24
-
1
tz.transition 2045, 10, :o6, 59238781, 24
-
1
tz.transition 2046, 3, :o5, 59242309, 24
-
1
tz.transition 2046, 10, :o6, 59247517, 24
-
1
tz.transition 2047, 3, :o5, 59251213, 24
-
1
tz.transition 2047, 10, :o6, 59256253, 24
-
1
tz.transition 2048, 3, :o5, 59259949, 24
-
1
tz.transition 2048, 10, :o6, 59264989, 24
-
1
tz.transition 2049, 3, :o5, 59268685, 24
-
1
tz.transition 2049, 10, :o6, 59273893, 24
-
1
tz.transition 2050, 3, :o5, 59277421, 24
-
1
tz.transition 2050, 10, :o6, 59282629, 24
-
end
-
end
-
end
-
end
-
end
-
1
module TZInfo
-
1
module Definitions
-
1
module Europe
-
1
module Athens
-
1
include TimezoneDefinition
-
-
1
timezone 'Europe/Athens' do |tz|
-
1
tz.offset :o0, 5692, 0, :LMT
-
1
tz.offset :o1, 5692, 0, :AMT
-
1
tz.offset :o2, 7200, 0, :EET
-
1
tz.offset :o3, 7200, 3600, :EEST
-
1
tz.offset :o4, 3600, 3600, :CEST
-
1
tz.offset :o5, 3600, 0, :CET
-
-
1
tz.transition 1895, 9, :o1, 52130529377, 21600
-
1
tz.transition 1916, 7, :o2, 3268447787, 1350
-
1
tz.transition 1932, 7, :o3, 29122745, 12
-
1
tz.transition 1932, 8, :o2, 19415611, 8
-
1
tz.transition 1941, 4, :o3, 29161097, 12
-
1
tz.transition 1941, 4, :o4, 19440915, 8
-
1
tz.transition 1942, 11, :o5, 58335973, 24
-
1
tz.transition 1943, 3, :o4, 58339523, 24
-
1
tz.transition 1943, 10, :o5, 29172017, 12
-
1
tz.transition 1944, 4, :o2, 58348427, 24
-
1
tz.transition 1952, 6, :o3, 29210333, 12
-
1
tz.transition 1952, 11, :o2, 19474547, 8
-
1
tz.transition 1975, 4, :o3, 166485600
-
1
tz.transition 1975, 11, :o2, 186184800
-
1
tz.transition 1976, 4, :o3, 198028800
-
1
tz.transition 1976, 10, :o2, 213753600
-
1
tz.transition 1977, 4, :o3, 228873600
-
1
tz.transition 1977, 9, :o2, 244080000
-
1
tz.transition 1978, 4, :o3, 260323200
-
1
tz.transition 1978, 9, :o2, 275446800
-
1
tz.transition 1979, 4, :o3, 291798000
-
1
tz.transition 1979, 9, :o2, 307407600
-
1
tz.transition 1980, 3, :o3, 323388000
-
1
tz.transition 1980, 9, :o2, 338936400
-
1
tz.transition 1981, 3, :o3, 354675600
-
1
tz.transition 1981, 9, :o2, 370400400
-
1
tz.transition 1982, 3, :o3, 386125200
-
1
tz.transition 1982, 9, :o2, 401850000
-
1
tz.transition 1983, 3, :o3, 417574800
-
1
tz.transition 1983, 9, :o2, 433299600
-
1
tz.transition 1984, 3, :o3, 449024400
-
1
tz.transition 1984, 9, :o2, 465354000
-
1
tz.transition 1985, 3, :o3, 481078800
-
1
tz.transition 1985, 9, :o2, 496803600
-
1
tz.transition 1986, 3, :o3, 512528400
-
1
tz.transition 1986, 9, :o2, 528253200
-
1
tz.transition 1987, 3, :o3, 543978000
-
1
tz.transition 1987, 9, :o2, 559702800
-
1
tz.transition 1988, 3, :o3, 575427600
-
1
tz.transition 1988, 9, :o2, 591152400
-
1
tz.transition 1989, 3, :o3, 606877200
-
1
tz.transition 1989, 9, :o2, 622602000
-
1
tz.transition 1990, 3, :o3, 638326800
-
1
tz.transition 1990, 9, :o2, 654656400
-
1
tz.transition 1991, 3, :o3, 670381200
-
1
tz.transition 1991, 9, :o2, 686106000
-
1
tz.transition 1992, 3, :o3, 701830800
-
1
tz.transition 1992, 9, :o2, 717555600
-
1
tz.transition 1993, 3, :o3, 733280400
-
1
tz.transition 1993, 9, :o2, 749005200
-
1
tz.transition 1994, 3, :o3, 764730000
-
1
tz.transition 1994, 9, :o2, 780454800
-
1
tz.transition 1995, 3, :o3, 796179600
-
1
tz.transition 1995, 9, :o2, 811904400
-
1
tz.transition 1996, 3, :o3, 828234000
-
1
tz.transition 1996, 10, :o2, 846378000
-
1
tz.transition 1997, 3, :o3, 859683600
-
1
tz.transition 1997, 10, :o2, 877827600
-
1
tz.transition 1998, 3, :o3, 891133200
-
1
tz.transition 1998, 10, :o2, 909277200
-
1
tz.transition 1999, 3, :o3, 922582800
-
1
tz.transition 1999, 10, :o2, 941331600
-
1
tz.transition 2000, 3, :o3, 954032400
-
1
tz.transition 2000, 10, :o2, 972781200
-
1
tz.transition 2001, 3, :o3, 985482000
-
1
tz.transition 2001, 10, :o2, 1004230800
-
1
tz.transition 2002, 3, :o3, 1017536400
-
1
tz.transition 2002, 10, :o2, 1035680400
-
1
tz.transition 2003, 3, :o3, 1048986000
-
1
tz.transition 2003, 10, :o2, 1067130000
-
1
tz.transition 2004, 3, :o3, 1080435600
-
1
tz.transition 2004, 10, :o2, 1099184400
-
1
tz.transition 2005, 3, :o3, 1111885200
-
1
tz.transition 2005, 10, :o2, 1130634000
-
1
tz.transition 2006, 3, :o3, 1143334800
-
1
tz.transition 2006, 10, :o2, 1162083600
-
1
tz.transition 2007, 3, :o3, 1174784400
-
1
tz.transition 2007, 10, :o2, 1193533200
-
1
tz.transition 2008, 3, :o3, 1206838800
-
1
tz.transition 2008, 10, :o2, 1224982800
-
1
tz.transition 2009, 3, :o3, 1238288400
-
1
tz.transition 2009, 10, :o2, 1256432400
-
1
tz.transition 2010, 3, :o3, 1269738000
-
1
tz.transition 2010, 10, :o2, 1288486800
-
1
tz.transition 2011, 3, :o3, 1301187600
-
1
tz.transition 2011, 10, :o2, 1319936400
-
1
tz.transition 2012, 3, :o3, 1332637200
-
1
tz.transition 2012, 10, :o2, 1351386000
-
1
tz.transition 2013, 3, :o3, 1364691600
-
1
tz.transition 2013, 10, :o2, 1382835600
-
1
tz.transition 2014, 3, :o3, 1396141200
-
1
tz.transition 2014, 10, :o2, 1414285200
-
1
tz.transition 2015, 3, :o3, 1427590800
-
1
tz.transition 2015, 10, :o2, 1445734800
-
1
tz.transition 2016, 3, :o3, 1459040400
-
1
tz.transition 2016, 10, :o2, 1477789200
-
1
tz.transition 2017, 3, :o3, 1490490000
-
1
tz.transition 2017, 10, :o2, 1509238800
-
1
tz.transition 2018, 3, :o3, 1521939600
-
1
tz.transition 2018, 10, :o2, 1540688400
-
1
tz.transition 2019, 3, :o3, 1553994000
-
1
tz.transition 2019, 10, :o2, 1572138000
-
1
tz.transition 2020, 3, :o3, 1585443600
-
1
tz.transition 2020, 10, :o2, 1603587600
-
1
tz.transition 2021, 3, :o3, 1616893200
-
1
tz.transition 2021, 10, :o2, 1635642000
-
1
tz.transition 2022, 3, :o3, 1648342800
-
1
tz.transition 2022, 10, :o2, 1667091600
-
1
tz.transition 2023, 3, :o3, 1679792400
-
1
tz.transition 2023, 10, :o2, 1698541200
-
1
tz.transition 2024, 3, :o3, 1711846800
-
1
tz.transition 2024, 10, :o2, 1729990800
-
1
tz.transition 2025, 3, :o3, 1743296400
-
1
tz.transition 2025, 10, :o2, 1761440400
-
1
tz.transition 2026, 3, :o3, 1774746000
-
1
tz.transition 2026, 10, :o2, 1792890000
-
1
tz.transition 2027, 3, :o3, 1806195600
-
1
tz.transition 2027, 10, :o2, 1824944400
-
1
tz.transition 2028, 3, :o3, 1837645200
-
1
tz.transition 2028, 10, :o2, 1856394000
-
1
tz.transition 2029, 3, :o3, 1869094800
-
1
tz.transition 2029, 10, :o2, 1887843600
-
1
tz.transition 2030, 3, :o3, 1901149200
-
1
tz.transition 2030, 10, :o2, 1919293200
-
1
tz.transition 2031, 3, :o3, 1932598800
-
1
tz.transition 2031, 10, :o2, 1950742800
-
1
tz.transition 2032, 3, :o3, 1964048400
-
1
tz.transition 2032, 10, :o2, 1982797200
-
1
tz.transition 2033, 3, :o3, 1995498000
-
1
tz.transition 2033, 10, :o2, 2014246800
-
1
tz.transition 2034, 3, :o3, 2026947600
-
1
tz.transition 2034, 10, :o2, 2045696400
-
1
tz.transition 2035, 3, :o3, 2058397200
-
1
tz.transition 2035, 10, :o2, 2077146000
-
1
tz.transition 2036, 3, :o3, 2090451600
-
1
tz.transition 2036, 10, :o2, 2108595600
-
1
tz.transition 2037, 3, :o3, 2121901200
-
1
tz.transition 2037, 10, :o2, 2140045200
-
1
tz.transition 2038, 3, :o3, 59172253, 24
-
1
tz.transition 2038, 10, :o2, 59177461, 24
-
1
tz.transition 2039, 3, :o3, 59180989, 24
-
1
tz.transition 2039, 10, :o2, 59186197, 24
-
1
tz.transition 2040, 3, :o3, 59189725, 24
-
1
tz.transition 2040, 10, :o2, 59194933, 24
-
1
tz.transition 2041, 3, :o3, 59198629, 24
-
1
tz.transition 2041, 10, :o2, 59203669, 24
-
1
tz.transition 2042, 3, :o3, 59207365, 24
-
1
tz.transition 2042, 10, :o2, 59212405, 24
-
1
tz.transition 2043, 3, :o3, 59216101, 24
-
1
tz.transition 2043, 10, :o2, 59221141, 24
-
1
tz.transition 2044, 3, :o3, 59224837, 24
-
1
tz.transition 2044, 10, :o2, 59230045, 24
-
1
tz.transition 2045, 3, :o3, 59233573, 24
-
1
tz.transition 2045, 10, :o2, 59238781, 24
-
1
tz.transition 2046, 3, :o3, 59242309, 24
-
1
tz.transition 2046, 10, :o2, 59247517, 24
-
1
tz.transition 2047, 3, :o3, 59251213, 24
-
1
tz.transition 2047, 10, :o2, 59256253, 24
-
1
tz.transition 2048, 3, :o3, 59259949, 24
-
1
tz.transition 2048, 10, :o2, 59264989, 24
-
1
tz.transition 2049, 3, :o3, 59268685, 24
-
1
tz.transition 2049, 10, :o2, 59273893, 24
-
1
tz.transition 2050, 3, :o3, 59277421, 24
-
1
tz.transition 2050, 10, :o2, 59282629, 24
-
end
-
end
-
end
-
end
-
end
-
1
module TZInfo
-
1
module Definitions
-
1
module Europe
-
1
module Belgrade
-
1
include TimezoneDefinition
-
-
1
timezone 'Europe/Belgrade' do |tz|
-
1
tz.offset :o0, 4920, 0, :LMT
-
1
tz.offset :o1, 3600, 0, :CET
-
1
tz.offset :o2, 3600, 3600, :CEST
-
-
1
tz.transition 1883, 12, :o1, 1734607039, 720
-
1
tz.transition 1941, 4, :o2, 29161241, 12
-
1
tz.transition 1942, 11, :o1, 58335973, 24
-
1
tz.transition 1943, 3, :o2, 58339501, 24
-
1
tz.transition 1943, 10, :o1, 58344037, 24
-
1
tz.transition 1944, 4, :o2, 58348405, 24
-
1
tz.transition 1944, 10, :o1, 58352773, 24
-
1
tz.transition 1945, 5, :o2, 58358005, 24
-
1
tz.transition 1945, 9, :o1, 58361149, 24
-
1
tz.transition 1983, 3, :o2, 417574800
-
1
tz.transition 1983, 9, :o1, 433299600
-
1
tz.transition 1984, 3, :o2, 449024400
-
1
tz.transition 1984, 9, :o1, 465354000
-
1
tz.transition 1985, 3, :o2, 481078800
-
1
tz.transition 1985, 9, :o1, 496803600
-
1
tz.transition 1986, 3, :o2, 512528400
-
1
tz.transition 1986, 9, :o1, 528253200
-
1
tz.transition 1987, 3, :o2, 543978000
-
1
tz.transition 1987, 9, :o1, 559702800
-
1
tz.transition 1988, 3, :o2, 575427600
-
1
tz.transition 1988, 9, :o1, 591152400
-
1
tz.transition 1989, 3, :o2, 606877200
-
1
tz.transition 1989, 9, :o1, 622602000
-
1
tz.transition 1990, 3, :o2, 638326800
-
1
tz.transition 1990, 9, :o1, 654656400
-
1
tz.transition 1991, 3, :o2, 670381200
-
1
tz.transition 1991, 9, :o1, 686106000
-
1
tz.transition 1992, 3, :o2, 701830800
-
1
tz.transition 1992, 9, :o1, 717555600
-
1
tz.transition 1993, 3, :o2, 733280400
-
1
tz.transition 1993, 9, :o1, 749005200
-
1
tz.transition 1994, 3, :o2, 764730000
-
1
tz.transition 1994, 9, :o1, 780454800
-
1
tz.transition 1995, 3, :o2, 796179600
-
1
tz.transition 1995, 9, :o1, 811904400
-
1
tz.transition 1996, 3, :o2, 828234000
-
1
tz.transition 1996, 10, :o1, 846378000
-
1
tz.transition 1997, 3, :o2, 859683600
-
1
tz.transition 1997, 10, :o1, 877827600
-
1
tz.transition 1998, 3, :o2, 891133200
-
1
tz.transition 1998, 10, :o1, 909277200
-
1
tz.transition 1999, 3, :o2, 922582800
-
1
tz.transition 1999, 10, :o1, 941331600
-
1
tz.transition 2000, 3, :o2, 954032400
-
1
tz.transition 2000, 10, :o1, 972781200
-
1
tz.transition 2001, 3, :o2, 985482000
-
1
tz.transition 2001, 10, :o1, 1004230800
-
1
tz.transition 2002, 3, :o2, 1017536400
-
1
tz.transition 2002, 10, :o1, 1035680400
-
1
tz.transition 2003, 3, :o2, 1048986000
-
1
tz.transition 2003, 10, :o1, 1067130000
-
1
tz.transition 2004, 3, :o2, 1080435600
-
1
tz.transition 2004, 10, :o1, 1099184400
-
1
tz.transition 2005, 3, :o2, 1111885200
-
1
tz.transition 2005, 10, :o1, 1130634000
-
1
tz.transition 2006, 3, :o2, 1143334800
-
1
tz.transition 2006, 10, :o1, 1162083600
-
1
tz.transition 2007, 3, :o2, 1174784400
-
1
tz.transition 2007, 10, :o1, 1193533200
-
1
tz.transition 2008, 3, :o2, 1206838800
-
1
tz.transition 2008, 10, :o1, 1224982800
-
1
tz.transition 2009, 3, :o2, 1238288400
-
1
tz.transition 2009, 10, :o1, 1256432400
-
1
tz.transition 2010, 3, :o2, 1269738000
-
1
tz.transition 2010, 10, :o1, 1288486800
-
1
tz.transition 2011, 3, :o2, 1301187600
-
1
tz.transition 2011, 10, :o1, 1319936400
-
1
tz.transition 2012, 3, :o2, 1332637200
-
1
tz.transition 2012, 10, :o1, 1351386000
-
1
tz.transition 2013, 3, :o2, 1364691600
-
1
tz.transition 2013, 10, :o1, 1382835600
-
1
tz.transition 2014, 3, :o2, 1396141200
-
1
tz.transition 2014, 10, :o1, 1414285200
-
1
tz.transition 2015, 3, :o2, 1427590800
-
1
tz.transition 2015, 10, :o1, 1445734800
-
1
tz.transition 2016, 3, :o2, 1459040400
-
1
tz.transition 2016, 10, :o1, 1477789200
-
1
tz.transition 2017, 3, :o2, 1490490000
-
1
tz.transition 2017, 10, :o1, 1509238800
-
1
tz.transition 2018, 3, :o2, 1521939600
-
1
tz.transition 2018, 10, :o1, 1540688400
-
1
tz.transition 2019, 3, :o2, 1553994000
-
1
tz.transition 2019, 10, :o1, 1572138000
-
1
tz.transition 2020, 3, :o2, 1585443600
-
1
tz.transition 2020, 10, :o1, 1603587600
-
1
tz.transition 2021, 3, :o2, 1616893200
-
1
tz.transition 2021, 10, :o1, 1635642000
-
1
tz.transition 2022, 3, :o2, 1648342800
-
1
tz.transition 2022, 10, :o1, 1667091600
-
1
tz.transition 2023, 3, :o2, 1679792400
-
1
tz.transition 2023, 10, :o1, 1698541200
-
1
tz.transition 2024, 3, :o2, 1711846800
-
1
tz.transition 2024, 10, :o1, 1729990800
-
1
tz.transition 2025, 3, :o2, 1743296400
-
1
tz.transition 2025, 10, :o1, 1761440400
-
1
tz.transition 2026, 3, :o2, 1774746000
-
1
tz.transition 2026, 10, :o1, 1792890000
-
1
tz.transition 2027, 3, :o2, 1806195600
-
1
tz.transition 2027, 10, :o1, 1824944400
-
1
tz.transition 2028, 3, :o2, 1837645200
-
1
tz.transition 2028, 10, :o1, 1856394000
-
1
tz.transition 2029, 3, :o2, 1869094800
-
1
tz.transition 2029, 10, :o1, 1887843600
-
1
tz.transition 2030, 3, :o2, 1901149200
-
1
tz.transition 2030, 10, :o1, 1919293200
-
1
tz.transition 2031, 3, :o2, 1932598800
-
1
tz.transition 2031, 10, :o1, 1950742800
-
1
tz.transition 2032, 3, :o2, 1964048400
-
1
tz.transition 2032, 10, :o1, 1982797200
-
1
tz.transition 2033, 3, :o2, 1995498000
-
1
tz.transition 2033, 10, :o1, 2014246800
-
1
tz.transition 2034, 3, :o2, 2026947600
-
1
tz.transition 2034, 10, :o1, 2045696400
-
1
tz.transition 2035, 3, :o2, 2058397200
-
1
tz.transition 2035, 10, :o1, 2077146000
-
1
tz.transition 2036, 3, :o2, 2090451600
-
1
tz.transition 2036, 10, :o1, 2108595600
-
1
tz.transition 2037, 3, :o2, 2121901200
-
1
tz.transition 2037, 10, :o1, 2140045200
-
1
tz.transition 2038, 3, :o2, 59172253, 24
-
1
tz.transition 2038, 10, :o1, 59177461, 24
-
1
tz.transition 2039, 3, :o2, 59180989, 24
-
1
tz.transition 2039, 10, :o1, 59186197, 24
-
1
tz.transition 2040, 3, :o2, 59189725, 24
-
1
tz.transition 2040, 10, :o1, 59194933, 24
-
1
tz.transition 2041, 3, :o2, 59198629, 24
-
1
tz.transition 2041, 10, :o1, 59203669, 24
-
1
tz.transition 2042, 3, :o2, 59207365, 24
-
1
tz.transition 2042, 10, :o1, 59212405, 24
-
1
tz.transition 2043, 3, :o2, 59216101, 24
-
1
tz.transition 2043, 10, :o1, 59221141, 24
-
1
tz.transition 2044, 3, :o2, 59224837, 24
-
1
tz.transition 2044, 10, :o1, 59230045, 24
-
1
tz.transition 2045, 3, :o2, 59233573, 24
-
1
tz.transition 2045, 10, :o1, 59238781, 24
-
1
tz.transition 2046, 3, :o2, 59242309, 24
-
1
tz.transition 2046, 10, :o1, 59247517, 24
-
1
tz.transition 2047, 3, :o2, 59251213, 24
-
1
tz.transition 2047, 10, :o1, 59256253, 24
-
1
tz.transition 2048, 3, :o2, 59259949, 24
-
1
tz.transition 2048, 10, :o1, 59264989, 24
-
1
tz.transition 2049, 3, :o2, 59268685, 24
-
1
tz.transition 2049, 10, :o1, 59273893, 24
-
1
tz.transition 2050, 3, :o2, 59277421, 24
-
1
tz.transition 2050, 10, :o1, 59282629, 24
-
end
-
end
-
end
-
end
-
end
-
1
module TZInfo
-
1
module Definitions
-
1
module Europe
-
1
module Berlin
-
1
include TimezoneDefinition
-
-
1
timezone 'Europe/Berlin' do |tz|
-
1
tz.offset :o0, 3208, 0, :LMT
-
1
tz.offset :o1, 3600, 0, :CET
-
1
tz.offset :o2, 3600, 3600, :CEST
-
1
tz.offset :o3, 3600, 7200, :CEMT
-
-
1
tz.transition 1893, 3, :o1, 26055588199, 10800
-
1
tz.transition 1916, 4, :o2, 29051813, 12
-
1
tz.transition 1916, 9, :o1, 58107299, 24
-
1
tz.transition 1917, 4, :o2, 58112029, 24
-
1
tz.transition 1917, 9, :o1, 58115725, 24
-
1
tz.transition 1918, 4, :o2, 58120765, 24
-
1
tz.transition 1918, 9, :o1, 58124461, 24
-
1
tz.transition 1940, 4, :o2, 58313293, 24
-
1
tz.transition 1942, 11, :o1, 58335973, 24
-
1
tz.transition 1943, 3, :o2, 58339501, 24
-
1
tz.transition 1943, 10, :o1, 58344037, 24
-
1
tz.transition 1944, 4, :o2, 58348405, 24
-
1
tz.transition 1944, 10, :o1, 58352773, 24
-
1
tz.transition 1945, 4, :o2, 58357141, 24
-
1
tz.transition 1945, 5, :o3, 4863199, 2
-
1
tz.transition 1945, 9, :o2, 4863445, 2
-
1
tz.transition 1945, 11, :o1, 58362661, 24
-
1
tz.transition 1946, 4, :o2, 58366189, 24
-
1
tz.transition 1946, 10, :o1, 58370413, 24
-
1
tz.transition 1947, 4, :o2, 29187379, 12
-
1
tz.transition 1947, 5, :o3, 58375597, 24
-
1
tz.transition 1947, 6, :o2, 4864731, 2
-
1
tz.transition 1947, 10, :o1, 58379125, 24
-
1
tz.transition 1948, 4, :o2, 58383829, 24
-
1
tz.transition 1948, 10, :o1, 58387861, 24
-
1
tz.transition 1949, 4, :o2, 58392397, 24
-
1
tz.transition 1949, 10, :o1, 58396597, 24
-
1
tz.transition 1980, 4, :o2, 323830800
-
1
tz.transition 1980, 9, :o1, 338950800
-
1
tz.transition 1981, 3, :o2, 354675600
-
1
tz.transition 1981, 9, :o1, 370400400
-
1
tz.transition 1982, 3, :o2, 386125200
-
1
tz.transition 1982, 9, :o1, 401850000
-
1
tz.transition 1983, 3, :o2, 417574800
-
1
tz.transition 1983, 9, :o1, 433299600
-
1
tz.transition 1984, 3, :o2, 449024400
-
1
tz.transition 1984, 9, :o1, 465354000
-
1
tz.transition 1985, 3, :o2, 481078800
-
1
tz.transition 1985, 9, :o1, 496803600
-
1
tz.transition 1986, 3, :o2, 512528400
-
1
tz.transition 1986, 9, :o1, 528253200
-
1
tz.transition 1987, 3, :o2, 543978000
-
1
tz.transition 1987, 9, :o1, 559702800
-
1
tz.transition 1988, 3, :o2, 575427600
-
1
tz.transition 1988, 9, :o1, 591152400
-
1
tz.transition 1989, 3, :o2, 606877200
-
1
tz.transition 1989, 9, :o1, 622602000
-
1
tz.transition 1990, 3, :o2, 638326800
-
1
tz.transition 1990, 9, :o1, 654656400
-
1
tz.transition 1991, 3, :o2, 670381200
-
1
tz.transition 1991, 9, :o1, 686106000
-
1
tz.transition 1992, 3, :o2, 701830800
-
1
tz.transition 1992, 9, :o1, 717555600
-
1
tz.transition 1993, 3, :o2, 733280400
-
1
tz.transition 1993, 9, :o1, 749005200
-
1
tz.transition 1994, 3, :o2, 764730000
-
1
tz.transition 1994, 9, :o1, 780454800
-
1
tz.transition 1995, 3, :o2, 796179600
-
1
tz.transition 1995, 9, :o1, 811904400
-
1
tz.transition 1996, 3, :o2, 828234000
-
1
tz.transition 1996, 10, :o1, 846378000
-
1
tz.transition 1997, 3, :o2, 859683600
-
1
tz.transition 1997, 10, :o1, 877827600
-
1
tz.transition 1998, 3, :o2, 891133200
-
1
tz.transition 1998, 10, :o1, 909277200
-
1
tz.transition 1999, 3, :o2, 922582800
-
1
tz.transition 1999, 10, :o1, 941331600
-
1
tz.transition 2000, 3, :o2, 954032400
-
1
tz.transition 2000, 10, :o1, 972781200
-
1
tz.transition 2001, 3, :o2, 985482000
-
1
tz.transition 2001, 10, :o1, 1004230800
-
1
tz.transition 2002, 3, :o2, 1017536400
-
1
tz.transition 2002, 10, :o1, 1035680400
-
1
tz.transition 2003, 3, :o2, 1048986000
-
1
tz.transition 2003, 10, :o1, 1067130000
-
1
tz.transition 2004, 3, :o2, 1080435600
-
1
tz.transition 2004, 10, :o1, 1099184400
-
1
tz.transition 2005, 3, :o2, 1111885200
-
1
tz.transition 2005, 10, :o1, 1130634000
-
1
tz.transition 2006, 3, :o2, 1143334800
-
1
tz.transition 2006, 10, :o1, 1162083600
-
1
tz.transition 2007, 3, :o2, 1174784400
-
1
tz.transition 2007, 10, :o1, 1193533200
-
1
tz.transition 2008, 3, :o2, 1206838800
-
1
tz.transition 2008, 10, :o1, 1224982800
-
1
tz.transition 2009, 3, :o2, 1238288400
-
1
tz.transition 2009, 10, :o1, 1256432400
-
1
tz.transition 2010, 3, :o2, 1269738000
-
1
tz.transition 2010, 10, :o1, 1288486800
-
1
tz.transition 2011, 3, :o2, 1301187600
-
1
tz.transition 2011, 10, :o1, 1319936400
-
1
tz.transition 2012, 3, :o2, 1332637200
-
1
tz.transition 2012, 10, :o1, 1351386000
-
1
tz.transition 2013, 3, :o2, 1364691600
-
1
tz.transition 2013, 10, :o1, 1382835600
-
1
tz.transition 2014, 3, :o2, 1396141200
-
1
tz.transition 2014, 10, :o1, 1414285200
-
1
tz.transition 2015, 3, :o2, 1427590800
-
1
tz.transition 2015, 10, :o1, 1445734800
-
1
tz.transition 2016, 3, :o2, 1459040400
-
1
tz.transition 2016, 10, :o1, 1477789200
-
1
tz.transition 2017, 3, :o2, 1490490000
-
1
tz.transition 2017, 10, :o1, 1509238800
-
1
tz.transition 2018, 3, :o2, 1521939600
-
1
tz.transition 2018, 10, :o1, 1540688400
-
1
tz.transition 2019, 3, :o2, 1553994000
-
1
tz.transition 2019, 10, :o1, 1572138000
-
1
tz.transition 2020, 3, :o2, 1585443600
-
1
tz.transition 2020, 10, :o1, 1603587600
-
1
tz.transition 2021, 3, :o2, 1616893200
-
1
tz.transition 2021, 10, :o1, 1635642000
-
1
tz.transition 2022, 3, :o2, 1648342800
-
1
tz.transition 2022, 10, :o1, 1667091600
-
1
tz.transition 2023, 3, :o2, 1679792400
-
1
tz.transition 2023, 10, :o1, 1698541200
-
1
tz.transition 2024, 3, :o2, 1711846800
-
1
tz.transition 2024, 10, :o1, 1729990800
-
1
tz.transition 2025, 3, :o2, 1743296400
-
1
tz.transition 2025, 10, :o1, 1761440400
-
1
tz.transition 2026, 3, :o2, 1774746000
-
1
tz.transition 2026, 10, :o1, 1792890000
-
1
tz.transition 2027, 3, :o2, 1806195600
-
1
tz.transition 2027, 10, :o1, 1824944400
-
1
tz.transition 2028, 3, :o2, 1837645200
-
1
tz.transition 2028, 10, :o1, 1856394000
-
1
tz.transition 2029, 3, :o2, 1869094800
-
1
tz.transition 2029, 10, :o1, 1887843600
-
1
tz.transition 2030, 3, :o2, 1901149200
-
1
tz.transition 2030, 10, :o1, 1919293200
-
1
tz.transition 2031, 3, :o2, 1932598800
-
1
tz.transition 2031, 10, :o1, 1950742800
-
1
tz.transition 2032, 3, :o2, 1964048400
-
1
tz.transition 2032, 10, :o1, 1982797200
-
1
tz.transition 2033, 3, :o2, 1995498000
-
1
tz.transition 2033, 10, :o1, 2014246800
-
1
tz.transition 2034, 3, :o2, 2026947600
-
1
tz.transition 2034, 10, :o1, 2045696400
-
1
tz.transition 2035, 3, :o2, 2058397200
-
1
tz.transition 2035, 10, :o1, 2077146000
-
1
tz.transition 2036, 3, :o2, 2090451600
-
1
tz.transition 2036, 10, :o1, 2108595600
-
1
tz.transition 2037, 3, :o2, 2121901200
-
1
tz.transition 2037, 10, :o1, 2140045200
-
1
tz.transition 2038, 3, :o2, 59172253, 24
-
1
tz.transition 2038, 10, :o1, 59177461, 24
-
1
tz.transition 2039, 3, :o2, 59180989, 24
-
1
tz.transition 2039, 10, :o1, 59186197, 24
-
1
tz.transition 2040, 3, :o2, 59189725, 24
-
1
tz.transition 2040, 10, :o1, 59194933, 24
-
1
tz.transition 2041, 3, :o2, 59198629, 24
-
1
tz.transition 2041, 10, :o1, 59203669, 24
-
1
tz.transition 2042, 3, :o2, 59207365, 24
-
1
tz.transition 2042, 10, :o1, 59212405, 24
-
1
tz.transition 2043, 3, :o2, 59216101, 24
-
1
tz.transition 2043, 10, :o1, 59221141, 24
-
1
tz.transition 2044, 3, :o2, 59224837, 24
-
1
tz.transition 2044, 10, :o1, 59230045, 24
-
1
tz.transition 2045, 3, :o2, 59233573, 24
-
1
tz.transition 2045, 10, :o1, 59238781, 24
-
1
tz.transition 2046, 3, :o2, 59242309, 24
-
1
tz.transition 2046, 10, :o1, 59247517, 24
-
1
tz.transition 2047, 3, :o2, 59251213, 24
-
1
tz.transition 2047, 10, :o1, 59256253, 24
-
1
tz.transition 2048, 3, :o2, 59259949, 24
-
1
tz.transition 2048, 10, :o1, 59264989, 24
-
1
tz.transition 2049, 3, :o2, 59268685, 24
-
1
tz.transition 2049, 10, :o1, 59273893, 24
-
1
tz.transition 2050, 3, :o2, 59277421, 24
-
1
tz.transition 2050, 10, :o1, 59282629, 24
-
end
-
end
-
end
-
end
-
end
-
1
module TZInfo
-
1
module Definitions
-
1
module Europe
-
1
module Bratislava
-
1
include TimezoneDefinition
-
-
1
linked_timezone 'Europe/Bratislava', 'Europe/Prague'
-
end
-
end
-
end
-
end
-
1
module TZInfo
-
1
module Definitions
-
1
module Europe
-
1
module Brussels
-
1
include TimezoneDefinition
-
-
1
timezone 'Europe/Brussels' do |tz|
-
1
tz.offset :o0, 1050, 0, :LMT
-
1
tz.offset :o1, 1050, 0, :BMT
-
1
tz.offset :o2, 0, 0, :WET
-
1
tz.offset :o3, 3600, 0, :CET
-
1
tz.offset :o4, 3600, 3600, :CEST
-
1
tz.offset :o5, 0, 3600, :WEST
-
-
1
tz.transition 1879, 12, :o1, 1386844121, 576
-
1
tz.transition 1892, 5, :o2, 1389438713, 576
-
1
tz.transition 1914, 11, :o3, 4840889, 2
-
1
tz.transition 1916, 4, :o4, 58103627, 24
-
1
tz.transition 1916, 9, :o3, 58107299, 24
-
1
tz.transition 1917, 4, :o4, 58112029, 24
-
1
tz.transition 1917, 9, :o3, 58115725, 24
-
1
tz.transition 1918, 4, :o4, 58120765, 24
-
1
tz.transition 1918, 9, :o3, 58124461, 24
-
1
tz.transition 1918, 11, :o2, 58125815, 24
-
1
tz.transition 1919, 3, :o5, 58128467, 24
-
1
tz.transition 1919, 10, :o2, 58133675, 24
-
1
tz.transition 1920, 2, :o5, 58136867, 24
-
1
tz.transition 1920, 10, :o2, 58142915, 24
-
1
tz.transition 1921, 3, :o5, 58146323, 24
-
1
tz.transition 1921, 10, :o2, 58151723, 24
-
1
tz.transition 1922, 3, :o5, 58155347, 24
-
1
tz.transition 1922, 10, :o2, 58160051, 24
-
1
tz.transition 1923, 4, :o5, 58164755, 24
-
1
tz.transition 1923, 10, :o2, 58168787, 24
-
1
tz.transition 1924, 3, :o5, 58172987, 24
-
1
tz.transition 1924, 10, :o2, 58177523, 24
-
1
tz.transition 1925, 4, :o5, 58181891, 24
-
1
tz.transition 1925, 10, :o2, 58186259, 24
-
1
tz.transition 1926, 4, :o5, 58190963, 24
-
1
tz.transition 1926, 10, :o2, 58194995, 24
-
1
tz.transition 1927, 4, :o5, 58199531, 24
-
1
tz.transition 1927, 10, :o2, 58203731, 24
-
1
tz.transition 1928, 4, :o5, 58208435, 24
-
1
tz.transition 1928, 10, :o2, 29106319, 12
-
1
tz.transition 1929, 4, :o5, 29108671, 12
-
1
tz.transition 1929, 10, :o2, 29110687, 12
-
1
tz.transition 1930, 4, :o5, 29112955, 12
-
1
tz.transition 1930, 10, :o2, 29115055, 12
-
1
tz.transition 1931, 4, :o5, 29117407, 12
-
1
tz.transition 1931, 10, :o2, 29119423, 12
-
1
tz.transition 1932, 4, :o5, 29121607, 12
-
1
tz.transition 1932, 10, :o2, 29123791, 12
-
1
tz.transition 1933, 3, :o5, 29125891, 12
-
1
tz.transition 1933, 10, :o2, 29128243, 12
-
1
tz.transition 1934, 4, :o5, 29130427, 12
-
1
tz.transition 1934, 10, :o2, 29132611, 12
-
1
tz.transition 1935, 3, :o5, 29134711, 12
-
1
tz.transition 1935, 10, :o2, 29136979, 12
-
1
tz.transition 1936, 4, :o5, 29139331, 12
-
1
tz.transition 1936, 10, :o2, 29141347, 12
-
1
tz.transition 1937, 4, :o5, 29143531, 12
-
1
tz.transition 1937, 10, :o2, 29145715, 12
-
1
tz.transition 1938, 3, :o5, 29147815, 12
-
1
tz.transition 1938, 10, :o2, 29150083, 12
-
1
tz.transition 1939, 4, :o5, 29152435, 12
-
1
tz.transition 1939, 11, :o2, 29155039, 12
-
1
tz.transition 1940, 2, :o5, 29156215, 12
-
1
tz.transition 1940, 5, :o4, 29157235, 12
-
1
tz.transition 1942, 11, :o3, 58335973, 24
-
1
tz.transition 1943, 3, :o4, 58339501, 24
-
1
tz.transition 1943, 10, :o3, 58344037, 24
-
1
tz.transition 1944, 4, :o4, 58348405, 24
-
1
tz.transition 1944, 9, :o3, 58352413, 24
-
1
tz.transition 1945, 4, :o4, 58357141, 24
-
1
tz.transition 1945, 9, :o3, 58361149, 24
-
1
tz.transition 1946, 5, :o4, 58367029, 24
-
1
tz.transition 1946, 10, :o3, 58370413, 24
-
1
tz.transition 1977, 4, :o4, 228877200
-
1
tz.transition 1977, 9, :o3, 243997200
-
1
tz.transition 1978, 4, :o4, 260326800
-
1
tz.transition 1978, 10, :o3, 276051600
-
1
tz.transition 1979, 4, :o4, 291776400
-
1
tz.transition 1979, 9, :o3, 307501200
-
1
tz.transition 1980, 4, :o4, 323830800
-
1
tz.transition 1980, 9, :o3, 338950800
-
1
tz.transition 1981, 3, :o4, 354675600
-
1
tz.transition 1981, 9, :o3, 370400400
-
1
tz.transition 1982, 3, :o4, 386125200
-
1
tz.transition 1982, 9, :o3, 401850000
-
1
tz.transition 1983, 3, :o4, 417574800
-
1
tz.transition 1983, 9, :o3, 433299600
-
1
tz.transition 1984, 3, :o4, 449024400
-
1
tz.transition 1984, 9, :o3, 465354000
-
1
tz.transition 1985, 3, :o4, 481078800
-
1
tz.transition 1985, 9, :o3, 496803600
-
1
tz.transition 1986, 3, :o4, 512528400
-
1
tz.transition 1986, 9, :o3, 528253200
-
1
tz.transition 1987, 3, :o4, 543978000
-
1
tz.transition 1987, 9, :o3, 559702800
-
1
tz.transition 1988, 3, :o4, 575427600
-
1
tz.transition 1988, 9, :o3, 591152400
-
1
tz.transition 1989, 3, :o4, 606877200
-
1
tz.transition 1989, 9, :o3, 622602000
-
1
tz.transition 1990, 3, :o4, 638326800
-
1
tz.transition 1990, 9, :o3, 654656400
-
1
tz.transition 1991, 3, :o4, 670381200
-
1
tz.transition 1991, 9, :o3, 686106000
-
1
tz.transition 1992, 3, :o4, 701830800
-
1
tz.transition 1992, 9, :o3, 717555600
-
1
tz.transition 1993, 3, :o4, 733280400
-
1
tz.transition 1993, 9, :o3, 749005200
-
1
tz.transition 1994, 3, :o4, 764730000
-
1
tz.transition 1994, 9, :o3, 780454800
-
1
tz.transition 1995, 3, :o4, 796179600
-
1
tz.transition 1995, 9, :o3, 811904400
-
1
tz.transition 1996, 3, :o4, 828234000
-
1
tz.transition 1996, 10, :o3, 846378000
-
1
tz.transition 1997, 3, :o4, 859683600
-
1
tz.transition 1997, 10, :o3, 877827600
-
1
tz.transition 1998, 3, :o4, 891133200
-
1
tz.transition 1998, 10, :o3, 909277200
-
1
tz.transition 1999, 3, :o4, 922582800
-
1
tz.transition 1999, 10, :o3, 941331600
-
1
tz.transition 2000, 3, :o4, 954032400
-
1
tz.transition 2000, 10, :o3, 972781200
-
1
tz.transition 2001, 3, :o4, 985482000
-
1
tz.transition 2001, 10, :o3, 1004230800
-
1
tz.transition 2002, 3, :o4, 1017536400
-
1
tz.transition 2002, 10, :o3, 1035680400
-
1
tz.transition 2003, 3, :o4, 1048986000
-
1
tz.transition 2003, 10, :o3, 1067130000
-
1
tz.transition 2004, 3, :o4, 1080435600
-
1
tz.transition 2004, 10, :o3, 1099184400
-
1
tz.transition 2005, 3, :o4, 1111885200
-
1
tz.transition 2005, 10, :o3, 1130634000
-
1
tz.transition 2006, 3, :o4, 1143334800
-
1
tz.transition 2006, 10, :o3, 1162083600
-
1
tz.transition 2007, 3, :o4, 1174784400
-
1
tz.transition 2007, 10, :o3, 1193533200
-
1
tz.transition 2008, 3, :o4, 1206838800
-
1
tz.transition 2008, 10, :o3, 1224982800
-
1
tz.transition 2009, 3, :o4, 1238288400
-
1
tz.transition 2009, 10, :o3, 1256432400
-
1
tz.transition 2010, 3, :o4, 1269738000
-
1
tz.transition 2010, 10, :o3, 1288486800
-
1
tz.transition 2011, 3, :o4, 1301187600
-
1
tz.transition 2011, 10, :o3, 1319936400
-
1
tz.transition 2012, 3, :o4, 1332637200
-
1
tz.transition 2012, 10, :o3, 1351386000
-
1
tz.transition 2013, 3, :o4, 1364691600
-
1
tz.transition 2013, 10, :o3, 1382835600
-
1
tz.transition 2014, 3, :o4, 1396141200
-
1
tz.transition 2014, 10, :o3, 1414285200
-
1
tz.transition 2015, 3, :o4, 1427590800
-
1
tz.transition 2015, 10, :o3, 1445734800
-
1
tz.transition 2016, 3, :o4, 1459040400
-
1
tz.transition 2016, 10, :o3, 1477789200
-
1
tz.transition 2017, 3, :o4, 1490490000
-
1
tz.transition 2017, 10, :o3, 1509238800
-
1
tz.transition 2018, 3, :o4, 1521939600
-
1
tz.transition 2018, 10, :o3, 1540688400
-
1
tz.transition 2019, 3, :o4, 1553994000
-
1
tz.transition 2019, 10, :o3, 1572138000
-
1
tz.transition 2020, 3, :o4, 1585443600
-
1
tz.transition 2020, 10, :o3, 1603587600
-
1
tz.transition 2021, 3, :o4, 1616893200
-
1
tz.transition 2021, 10, :o3, 1635642000
-
1
tz.transition 2022, 3, :o4, 1648342800
-
1
tz.transition 2022, 10, :o3, 1667091600
-
1
tz.transition 2023, 3, :o4, 1679792400
-
1
tz.transition 2023, 10, :o3, 1698541200
-
1
tz.transition 2024, 3, :o4, 1711846800
-
1
tz.transition 2024, 10, :o3, 1729990800
-
1
tz.transition 2025, 3, :o4, 1743296400
-
1
tz.transition 2025, 10, :o3, 1761440400
-
1
tz.transition 2026, 3, :o4, 1774746000
-
1
tz.transition 2026, 10, :o3, 1792890000
-
1
tz.transition 2027, 3, :o4, 1806195600
-
1
tz.transition 2027, 10, :o3, 1824944400
-
1
tz.transition 2028, 3, :o4, 1837645200
-
1
tz.transition 2028, 10, :o3, 1856394000
-
1
tz.transition 2029, 3, :o4, 1869094800
-
1
tz.transition 2029, 10, :o3, 1887843600
-
1
tz.transition 2030, 3, :o4, 1901149200
-
1
tz.transition 2030, 10, :o3, 1919293200
-
1
tz.transition 2031, 3, :o4, 1932598800
-
1
tz.transition 2031, 10, :o3, 1950742800
-
1
tz.transition 2032, 3, :o4, 1964048400
-
1
tz.transition 2032, 10, :o3, 1982797200
-
1
tz.transition 2033, 3, :o4, 1995498000
-
1
tz.transition 2033, 10, :o3, 2014246800
-
1
tz.transition 2034, 3, :o4, 2026947600
-
1
tz.transition 2034, 10, :o3, 2045696400
-
1
tz.transition 2035, 3, :o4, 2058397200
-
1
tz.transition 2035, 10, :o3, 2077146000
-
1
tz.transition 2036, 3, :o4, 2090451600
-
1
tz.transition 2036, 10, :o3, 2108595600
-
1
tz.transition 2037, 3, :o4, 2121901200
-
1
tz.transition 2037, 10, :o3, 2140045200
-
1
tz.transition 2038, 3, :o4, 59172253, 24
-
1
tz.transition 2038, 10, :o3, 59177461, 24
-
1
tz.transition 2039, 3, :o4, 59180989, 24
-
1
tz.transition 2039, 10, :o3, 59186197, 24
-
1
tz.transition 2040, 3, :o4, 59189725, 24
-
1
tz.transition 2040, 10, :o3, 59194933, 24
-
1
tz.transition 2041, 3, :o4, 59198629, 24
-
1
tz.transition 2041, 10, :o3, 59203669, 24
-
1
tz.transition 2042, 3, :o4, 59207365, 24
-
1
tz.transition 2042, 10, :o3, 59212405, 24
-
1
tz.transition 2043, 3, :o4, 59216101, 24
-
1
tz.transition 2043, 10, :o3, 59221141, 24
-
1
tz.transition 2044, 3, :o4, 59224837, 24
-
1
tz.transition 2044, 10, :o3, 59230045, 24
-
1
tz.transition 2045, 3, :o4, 59233573, 24
-
1
tz.transition 2045, 10, :o3, 59238781, 24
-
1
tz.transition 2046, 3, :o4, 59242309, 24
-
1
tz.transition 2046, 10, :o3, 59247517, 24
-
1
tz.transition 2047, 3, :o4, 59251213, 24
-
1
tz.transition 2047, 10, :o3, 59256253, 24
-
1
tz.transition 2048, 3, :o4, 59259949, 24
-
1
tz.transition 2048, 10, :o3, 59264989, 24
-
1
tz.transition 2049, 3, :o4, 59268685, 24
-
1
tz.transition 2049, 10, :o3, 59273893, 24
-
1
tz.transition 2050, 3, :o4, 59277421, 24
-
1
tz.transition 2050, 10, :o3, 59282629, 24
-
end
-
end
-
end
-
end
-
end
-
1
module TZInfo
-
1
module Definitions
-
1
module Europe
-
1
module Bucharest
-
1
include TimezoneDefinition
-
-
1
timezone 'Europe/Bucharest' do |tz|
-
1
tz.offset :o0, 6264, 0, :LMT
-
1
tz.offset :o1, 6264, 0, :BMT
-
1
tz.offset :o2, 7200, 0, :EET
-
1
tz.offset :o3, 7200, 3600, :EEST
-
-
1
tz.transition 1891, 9, :o1, 964802571, 400
-
1
tz.transition 1931, 7, :o2, 970618571, 400
-
1
tz.transition 1932, 5, :o3, 29122181, 12
-
1
tz.transition 1932, 10, :o2, 29123789, 12
-
1
tz.transition 1933, 4, :o3, 29125973, 12
-
1
tz.transition 1933, 9, :o2, 29128157, 12
-
1
tz.transition 1934, 4, :o3, 29130425, 12
-
1
tz.transition 1934, 10, :o2, 29132609, 12
-
1
tz.transition 1935, 4, :o3, 29134793, 12
-
1
tz.transition 1935, 10, :o2, 29136977, 12
-
1
tz.transition 1936, 4, :o3, 29139161, 12
-
1
tz.transition 1936, 10, :o2, 29141345, 12
-
1
tz.transition 1937, 4, :o3, 29143529, 12
-
1
tz.transition 1937, 10, :o2, 29145713, 12
-
1
tz.transition 1938, 4, :o3, 29147897, 12
-
1
tz.transition 1938, 10, :o2, 29150081, 12
-
1
tz.transition 1939, 4, :o3, 29152265, 12
-
1
tz.transition 1939, 9, :o2, 29154449, 12
-
1
tz.transition 1979, 5, :o3, 296604000
-
1
tz.transition 1979, 9, :o2, 307486800
-
1
tz.transition 1980, 4, :o3, 323816400
-
1
tz.transition 1980, 9, :o2, 338940000
-
1
tz.transition 1981, 3, :o3, 354672000
-
1
tz.transition 1981, 9, :o2, 370396800
-
1
tz.transition 1982, 3, :o3, 386121600
-
1
tz.transition 1982, 9, :o2, 401846400
-
1
tz.transition 1983, 3, :o3, 417571200
-
1
tz.transition 1983, 9, :o2, 433296000
-
1
tz.transition 1984, 3, :o3, 449020800
-
1
tz.transition 1984, 9, :o2, 465350400
-
1
tz.transition 1985, 3, :o3, 481075200
-
1
tz.transition 1985, 9, :o2, 496800000
-
1
tz.transition 1986, 3, :o3, 512524800
-
1
tz.transition 1986, 9, :o2, 528249600
-
1
tz.transition 1987, 3, :o3, 543974400
-
1
tz.transition 1987, 9, :o2, 559699200
-
1
tz.transition 1988, 3, :o3, 575424000
-
1
tz.transition 1988, 9, :o2, 591148800
-
1
tz.transition 1989, 3, :o3, 606873600
-
1
tz.transition 1989, 9, :o2, 622598400
-
1
tz.transition 1990, 3, :o3, 638323200
-
1
tz.transition 1990, 9, :o2, 654652800
-
1
tz.transition 1991, 3, :o3, 670370400
-
1
tz.transition 1991, 9, :o2, 686095200
-
1
tz.transition 1992, 3, :o3, 701820000
-
1
tz.transition 1992, 9, :o2, 717544800
-
1
tz.transition 1993, 3, :o3, 733269600
-
1
tz.transition 1993, 9, :o2, 748994400
-
1
tz.transition 1994, 3, :o3, 764719200
-
1
tz.transition 1994, 9, :o2, 780440400
-
1
tz.transition 1995, 3, :o3, 796168800
-
1
tz.transition 1995, 9, :o2, 811890000
-
1
tz.transition 1996, 3, :o3, 828223200
-
1
tz.transition 1996, 10, :o2, 846363600
-
1
tz.transition 1997, 3, :o3, 859683600
-
1
tz.transition 1997, 10, :o2, 877827600
-
1
tz.transition 1998, 3, :o3, 891133200
-
1
tz.transition 1998, 10, :o2, 909277200
-
1
tz.transition 1999, 3, :o3, 922582800
-
1
tz.transition 1999, 10, :o2, 941331600
-
1
tz.transition 2000, 3, :o3, 954032400
-
1
tz.transition 2000, 10, :o2, 972781200
-
1
tz.transition 2001, 3, :o3, 985482000
-
1
tz.transition 2001, 10, :o2, 1004230800
-
1
tz.transition 2002, 3, :o3, 1017536400
-
1
tz.transition 2002, 10, :o2, 1035680400
-
1
tz.transition 2003, 3, :o3, 1048986000
-
1
tz.transition 2003, 10, :o2, 1067130000
-
1
tz.transition 2004, 3, :o3, 1080435600
-
1
tz.transition 2004, 10, :o2, 1099184400
-
1
tz.transition 2005, 3, :o3, 1111885200
-
1
tz.transition 2005, 10, :o2, 1130634000
-
1
tz.transition 2006, 3, :o3, 1143334800
-
1
tz.transition 2006, 10, :o2, 1162083600
-
1
tz.transition 2007, 3, :o3, 1174784400
-
1
tz.transition 2007, 10, :o2, 1193533200
-
1
tz.transition 2008, 3, :o3, 1206838800
-
1
tz.transition 2008, 10, :o2, 1224982800
-
1
tz.transition 2009, 3, :o3, 1238288400
-
1
tz.transition 2009, 10, :o2, 1256432400
-
1
tz.transition 2010, 3, :o3, 1269738000
-
1
tz.transition 2010, 10, :o2, 1288486800
-
1
tz.transition 2011, 3, :o3, 1301187600
-
1
tz.transition 2011, 10, :o2, 1319936400
-
1
tz.transition 2012, 3, :o3, 1332637200
-
1
tz.transition 2012, 10, :o2, 1351386000
-
1
tz.transition 2013, 3, :o3, 1364691600
-
1
tz.transition 2013, 10, :o2, 1382835600
-
1
tz.transition 2014, 3, :o3, 1396141200
-
1
tz.transition 2014, 10, :o2, 1414285200
-
1
tz.transition 2015, 3, :o3, 1427590800
-
1
tz.transition 2015, 10, :o2, 1445734800
-
1
tz.transition 2016, 3, :o3, 1459040400
-
1
tz.transition 2016, 10, :o2, 1477789200
-
1
tz.transition 2017, 3, :o3, 1490490000
-
1
tz.transition 2017, 10, :o2, 1509238800
-
1
tz.transition 2018, 3, :o3, 1521939600
-
1
tz.transition 2018, 10, :o2, 1540688400
-
1
tz.transition 2019, 3, :o3, 1553994000
-
1
tz.transition 2019, 10, :o2, 1572138000
-
1
tz.transition 2020, 3, :o3, 1585443600
-
1
tz.transition 2020, 10, :o2, 1603587600
-
1
tz.transition 2021, 3, :o3, 1616893200
-
1
tz.transition 2021, 10, :o2, 1635642000
-
1
tz.transition 2022, 3, :o3, 1648342800
-
1
tz.transition 2022, 10, :o2, 1667091600
-
1
tz.transition 2023, 3, :o3, 1679792400
-
1
tz.transition 2023, 10, :o2, 1698541200
-
1
tz.transition 2024, 3, :o3, 1711846800
-
1
tz.transition 2024, 10, :o2, 1729990800
-
1
tz.transition 2025, 3, :o3, 1743296400
-
1
tz.transition 2025, 10, :o2, 1761440400
-
1
tz.transition 2026, 3, :o3, 1774746000
-
1
tz.transition 2026, 10, :o2, 1792890000
-
1
tz.transition 2027, 3, :o3, 1806195600
-
1
tz.transition 2027, 10, :o2, 1824944400
-
1
tz.transition 2028, 3, :o3, 1837645200
-
1
tz.transition 2028, 10, :o2, 1856394000
-
1
tz.transition 2029, 3, :o3, 1869094800
-
1
tz.transition 2029, 10, :o2, 1887843600
-
1
tz.transition 2030, 3, :o3, 1901149200
-
1
tz.transition 2030, 10, :o2, 1919293200
-
1
tz.transition 2031, 3, :o3, 1932598800
-
1
tz.transition 2031, 10, :o2, 1950742800
-
1
tz.transition 2032, 3, :o3, 1964048400
-
1
tz.transition 2032, 10, :o2, 1982797200
-
1
tz.transition 2033, 3, :o3, 1995498000
-
1
tz.transition 2033, 10, :o2, 2014246800
-
1
tz.transition 2034, 3, :o3, 2026947600
-
1
tz.transition 2034, 10, :o2, 2045696400
-
1
tz.transition 2035, 3, :o3, 2058397200
-
1
tz.transition 2035, 10, :o2, 2077146000
-
1
tz.transition 2036, 3, :o3, 2090451600
-
1
tz.transition 2036, 10, :o2, 2108595600
-
1
tz.transition 2037, 3, :o3, 2121901200
-
1
tz.transition 2037, 10, :o2, 2140045200
-
1
tz.transition 2038, 3, :o3, 59172253, 24
-
1
tz.transition 2038, 10, :o2, 59177461, 24
-
1
tz.transition 2039, 3, :o3, 59180989, 24
-
1
tz.transition 2039, 10, :o2, 59186197, 24
-
1
tz.transition 2040, 3, :o3, 59189725, 24
-
1
tz.transition 2040, 10, :o2, 59194933, 24
-
1
tz.transition 2041, 3, :o3, 59198629, 24
-
1
tz.transition 2041, 10, :o2, 59203669, 24
-
1
tz.transition 2042, 3, :o3, 59207365, 24
-
1
tz.transition 2042, 10, :o2, 59212405, 24
-
1
tz.transition 2043, 3, :o3, 59216101, 24
-
1
tz.transition 2043, 10, :o2, 59221141, 24
-
1
tz.transition 2044, 3, :o3, 59224837, 24
-
1
tz.transition 2044, 10, :o2, 59230045, 24
-
1
tz.transition 2045, 3, :o3, 59233573, 24
-
1
tz.transition 2045, 10, :o2, 59238781, 24
-
1
tz.transition 2046, 3, :o3, 59242309, 24
-
1
tz.transition 2046, 10, :o2, 59247517, 24
-
1
tz.transition 2047, 3, :o3, 59251213, 24
-
1
tz.transition 2047, 10, :o2, 59256253, 24
-
1
tz.transition 2048, 3, :o3, 59259949, 24
-
1
tz.transition 2048, 10, :o2, 59264989, 24
-
1
tz.transition 2049, 3, :o3, 59268685, 24
-
1
tz.transition 2049, 10, :o2, 59273893, 24
-
1
tz.transition 2050, 3, :o3, 59277421, 24
-
1
tz.transition 2050, 10, :o2, 59282629, 24
-
end
-
end
-
end
-
end
-
end
-
1
module TZInfo
-
1
module Definitions
-
1
module Europe
-
1
module Budapest
-
1
include TimezoneDefinition
-
-
1
timezone 'Europe/Budapest' do |tz|
-
1
tz.offset :o0, 4580, 0, :LMT
-
1
tz.offset :o1, 3600, 0, :CET
-
1
tz.offset :o2, 3600, 3600, :CEST
-
-
1
tz.transition 1890, 9, :o1, 10418291051, 4320
-
1
tz.transition 1916, 4, :o2, 29051813, 12
-
1
tz.transition 1916, 9, :o1, 58107299, 24
-
1
tz.transition 1917, 4, :o2, 58112029, 24
-
1
tz.transition 1917, 9, :o1, 58115725, 24
-
1
tz.transition 1918, 4, :o2, 29060215, 12
-
1
tz.transition 1918, 9, :o1, 58124773, 24
-
1
tz.transition 1919, 4, :o2, 29064763, 12
-
1
tz.transition 1919, 9, :o1, 58133197, 24
-
1
tz.transition 1920, 4, :o2, 29069035, 12
-
1
tz.transition 1920, 9, :o1, 58142341, 24
-
1
tz.transition 1941, 4, :o2, 58322173, 24
-
1
tz.transition 1942, 11, :o1, 58335973, 24
-
1
tz.transition 1943, 3, :o2, 58339501, 24
-
1
tz.transition 1943, 10, :o1, 58344037, 24
-
1
tz.transition 1944, 4, :o2, 58348405, 24
-
1
tz.transition 1944, 10, :o1, 58352773, 24
-
1
tz.transition 1945, 5, :o2, 29178929, 12
-
1
tz.transition 1945, 11, :o1, 29181149, 12
-
1
tz.transition 1946, 3, :o2, 58365853, 24
-
1
tz.transition 1946, 10, :o1, 58370389, 24
-
1
tz.transition 1947, 4, :o2, 58374757, 24
-
1
tz.transition 1947, 10, :o1, 58379125, 24
-
1
tz.transition 1948, 4, :o2, 58383493, 24
-
1
tz.transition 1948, 10, :o1, 58387861, 24
-
1
tz.transition 1949, 4, :o2, 58392397, 24
-
1
tz.transition 1949, 10, :o1, 58396597, 24
-
1
tz.transition 1950, 4, :o2, 58401325, 24
-
1
tz.transition 1950, 10, :o1, 58405861, 24
-
1
tz.transition 1954, 5, :o2, 58437251, 24
-
1
tz.transition 1954, 10, :o1, 29220221, 12
-
1
tz.transition 1955, 5, :o2, 58446011, 24
-
1
tz.transition 1955, 10, :o1, 29224601, 12
-
1
tz.transition 1956, 6, :o2, 58455059, 24
-
1
tz.transition 1956, 9, :o1, 29228957, 12
-
1
tz.transition 1957, 6, :o2, 4871983, 2
-
1
tz.transition 1957, 9, :o1, 58466653, 24
-
1
tz.transition 1980, 4, :o2, 323827200
-
1
tz.transition 1980, 9, :o1, 338950800
-
1
tz.transition 1981, 3, :o2, 354675600
-
1
tz.transition 1981, 9, :o1, 370400400
-
1
tz.transition 1982, 3, :o2, 386125200
-
1
tz.transition 1982, 9, :o1, 401850000
-
1
tz.transition 1983, 3, :o2, 417574800
-
1
tz.transition 1983, 9, :o1, 433299600
-
1
tz.transition 1984, 3, :o2, 449024400
-
1
tz.transition 1984, 9, :o1, 465354000
-
1
tz.transition 1985, 3, :o2, 481078800
-
1
tz.transition 1985, 9, :o1, 496803600
-
1
tz.transition 1986, 3, :o2, 512528400
-
1
tz.transition 1986, 9, :o1, 528253200
-
1
tz.transition 1987, 3, :o2, 543978000
-
1
tz.transition 1987, 9, :o1, 559702800
-
1
tz.transition 1988, 3, :o2, 575427600
-
1
tz.transition 1988, 9, :o1, 591152400
-
1
tz.transition 1989, 3, :o2, 606877200
-
1
tz.transition 1989, 9, :o1, 622602000
-
1
tz.transition 1990, 3, :o2, 638326800
-
1
tz.transition 1990, 9, :o1, 654656400
-
1
tz.transition 1991, 3, :o2, 670381200
-
1
tz.transition 1991, 9, :o1, 686106000
-
1
tz.transition 1992, 3, :o2, 701830800
-
1
tz.transition 1992, 9, :o1, 717555600
-
1
tz.transition 1993, 3, :o2, 733280400
-
1
tz.transition 1993, 9, :o1, 749005200
-
1
tz.transition 1994, 3, :o2, 764730000
-
1
tz.transition 1994, 9, :o1, 780454800
-
1
tz.transition 1995, 3, :o2, 796179600
-
1
tz.transition 1995, 9, :o1, 811904400
-
1
tz.transition 1996, 3, :o2, 828234000
-
1
tz.transition 1996, 10, :o1, 846378000
-
1
tz.transition 1997, 3, :o2, 859683600
-
1
tz.transition 1997, 10, :o1, 877827600
-
1
tz.transition 1998, 3, :o2, 891133200
-
1
tz.transition 1998, 10, :o1, 909277200
-
1
tz.transition 1999, 3, :o2, 922582800
-
1
tz.transition 1999, 10, :o1, 941331600
-
1
tz.transition 2000, 3, :o2, 954032400
-
1
tz.transition 2000, 10, :o1, 972781200
-
1
tz.transition 2001, 3, :o2, 985482000
-
1
tz.transition 2001, 10, :o1, 1004230800
-
1
tz.transition 2002, 3, :o2, 1017536400
-
1
tz.transition 2002, 10, :o1, 1035680400
-
1
tz.transition 2003, 3, :o2, 1048986000
-
1
tz.transition 2003, 10, :o1, 1067130000
-
1
tz.transition 2004, 3, :o2, 1080435600
-
1
tz.transition 2004, 10, :o1, 1099184400
-
1
tz.transition 2005, 3, :o2, 1111885200
-
1
tz.transition 2005, 10, :o1, 1130634000
-
1
tz.transition 2006, 3, :o2, 1143334800
-
1
tz.transition 2006, 10, :o1, 1162083600
-
1
tz.transition 2007, 3, :o2, 1174784400
-
1
tz.transition 2007, 10, :o1, 1193533200
-
1
tz.transition 2008, 3, :o2, 1206838800
-
1
tz.transition 2008, 10, :o1, 1224982800
-
1
tz.transition 2009, 3, :o2, 1238288400
-
1
tz.transition 2009, 10, :o1, 1256432400
-
1
tz.transition 2010, 3, :o2, 1269738000
-
1
tz.transition 2010, 10, :o1, 1288486800
-
1
tz.transition 2011, 3, :o2, 1301187600
-
1
tz.transition 2011, 10, :o1, 1319936400
-
1
tz.transition 2012, 3, :o2, 1332637200
-
1
tz.transition 2012, 10, :o1, 1351386000
-
1
tz.transition 2013, 3, :o2, 1364691600
-
1
tz.transition 2013, 10, :o1, 1382835600
-
1
tz.transition 2014, 3, :o2, 1396141200
-
1
tz.transition 2014, 10, :o1, 1414285200
-
1
tz.transition 2015, 3, :o2, 1427590800
-
1
tz.transition 2015, 10, :o1, 1445734800
-
1
tz.transition 2016, 3, :o2, 1459040400
-
1
tz.transition 2016, 10, :o1, 1477789200
-
1
tz.transition 2017, 3, :o2, 1490490000
-
1
tz.transition 2017, 10, :o1, 1509238800
-
1
tz.transition 2018, 3, :o2, 1521939600
-
1
tz.transition 2018, 10, :o1, 1540688400
-
1
tz.transition 2019, 3, :o2, 1553994000
-
1
tz.transition 2019, 10, :o1, 1572138000
-
1
tz.transition 2020, 3, :o2, 1585443600
-
1
tz.transition 2020, 10, :o1, 1603587600
-
1
tz.transition 2021, 3, :o2, 1616893200
-
1
tz.transition 2021, 10, :o1, 1635642000
-
1
tz.transition 2022, 3, :o2, 1648342800
-
1
tz.transition 2022, 10, :o1, 1667091600
-
1
tz.transition 2023, 3, :o2, 1679792400
-
1
tz.transition 2023, 10, :o1, 1698541200
-
1
tz.transition 2024, 3, :o2, 1711846800
-
1
tz.transition 2024, 10, :o1, 1729990800
-
1
tz.transition 2025, 3, :o2, 1743296400
-
1
tz.transition 2025, 10, :o1, 1761440400
-
1
tz.transition 2026, 3, :o2, 1774746000
-
1
tz.transition 2026, 10, :o1, 1792890000
-
1
tz.transition 2027, 3, :o2, 1806195600
-
1
tz.transition 2027, 10, :o1, 1824944400
-
1
tz.transition 2028, 3, :o2, 1837645200
-
1
tz.transition 2028, 10, :o1, 1856394000
-
1
tz.transition 2029, 3, :o2, 1869094800
-
1
tz.transition 2029, 10, :o1, 1887843600
-
1
tz.transition 2030, 3, :o2, 1901149200
-
1
tz.transition 2030, 10, :o1, 1919293200
-
1
tz.transition 2031, 3, :o2, 1932598800
-
1
tz.transition 2031, 10, :o1, 1950742800
-
1
tz.transition 2032, 3, :o2, 1964048400
-
1
tz.transition 2032, 10, :o1, 1982797200
-
1
tz.transition 2033, 3, :o2, 1995498000
-
1
tz.transition 2033, 10, :o1, 2014246800
-
1
tz.transition 2034, 3, :o2, 2026947600
-
1
tz.transition 2034, 10, :o1, 2045696400
-
1
tz.transition 2035, 3, :o2, 2058397200
-
1
tz.transition 2035, 10, :o1, 2077146000
-
1
tz.transition 2036, 3, :o2, 2090451600
-
1
tz.transition 2036, 10, :o1, 2108595600
-
1
tz.transition 2037, 3, :o2, 2121901200
-
1
tz.transition 2037, 10, :o1, 2140045200
-
1
tz.transition 2038, 3, :o2, 59172253, 24
-
1
tz.transition 2038, 10, :o1, 59177461, 24
-
1
tz.transition 2039, 3, :o2, 59180989, 24
-
1
tz.transition 2039, 10, :o1, 59186197, 24
-
1
tz.transition 2040, 3, :o2, 59189725, 24
-
1
tz.transition 2040, 10, :o1, 59194933, 24
-
1
tz.transition 2041, 3, :o2, 59198629, 24
-
1
tz.transition 2041, 10, :o1, 59203669, 24
-
1
tz.transition 2042, 3, :o2, 59207365, 24
-
1
tz.transition 2042, 10, :o1, 59212405, 24
-
1
tz.transition 2043, 3, :o2, 59216101, 24
-
1
tz.transition 2043, 10, :o1, 59221141, 24
-
1
tz.transition 2044, 3, :o2, 59224837, 24
-
1
tz.transition 2044, 10, :o1, 59230045, 24
-
1
tz.transition 2045, 3, :o2, 59233573, 24
-
1
tz.transition 2045, 10, :o1, 59238781, 24
-
1
tz.transition 2046, 3, :o2, 59242309, 24
-
1
tz.transition 2046, 10, :o1, 59247517, 24
-
1
tz.transition 2047, 3, :o2, 59251213, 24
-
1
tz.transition 2047, 10, :o1, 59256253, 24
-
1
tz.transition 2048, 3, :o2, 59259949, 24
-
1
tz.transition 2048, 10, :o1, 59264989, 24
-
1
tz.transition 2049, 3, :o2, 59268685, 24
-
1
tz.transition 2049, 10, :o1, 59273893, 24
-
1
tz.transition 2050, 3, :o2, 59277421, 24
-
1
tz.transition 2050, 10, :o1, 59282629, 24
-
end
-
end
-
end
-
end
-
end
-
1
module TZInfo
-
1
module Definitions
-
1
module Europe
-
1
module Copenhagen
-
1
include TimezoneDefinition
-
-
1
timezone 'Europe/Copenhagen' do |tz|
-
1
tz.offset :o0, 3020, 0, :LMT
-
1
tz.offset :o1, 3020, 0, :CMT
-
1
tz.offset :o2, 3600, 0, :CET
-
1
tz.offset :o3, 3600, 3600, :CEST
-
-
1
tz.transition 1889, 12, :o1, 10417111769, 4320
-
1
tz.transition 1893, 12, :o2, 10423423289, 4320
-
1
tz.transition 1916, 5, :o3, 29051981, 12
-
1
tz.transition 1916, 9, :o2, 19369099, 8
-
1
tz.transition 1940, 5, :o3, 58314347, 24
-
1
tz.transition 1942, 11, :o2, 58335973, 24
-
1
tz.transition 1943, 3, :o3, 58339501, 24
-
1
tz.transition 1943, 10, :o2, 58344037, 24
-
1
tz.transition 1944, 4, :o3, 58348405, 24
-
1
tz.transition 1944, 10, :o2, 58352773, 24
-
1
tz.transition 1945, 4, :o3, 58357141, 24
-
1
tz.transition 1945, 8, :o2, 58360381, 24
-
1
tz.transition 1946, 5, :o3, 58366597, 24
-
1
tz.transition 1946, 9, :o2, 58369549, 24
-
1
tz.transition 1947, 5, :o3, 58375429, 24
-
1
tz.transition 1947, 8, :o2, 58377781, 24
-
1
tz.transition 1948, 5, :o3, 58384333, 24
-
1
tz.transition 1948, 8, :o2, 58386517, 24
-
1
tz.transition 1980, 4, :o3, 323830800
-
1
tz.transition 1980, 9, :o2, 338950800
-
1
tz.transition 1981, 3, :o3, 354675600
-
1
tz.transition 1981, 9, :o2, 370400400
-
1
tz.transition 1982, 3, :o3, 386125200
-
1
tz.transition 1982, 9, :o2, 401850000
-
1
tz.transition 1983, 3, :o3, 417574800
-
1
tz.transition 1983, 9, :o2, 433299600
-
1
tz.transition 1984, 3, :o3, 449024400
-
1
tz.transition 1984, 9, :o2, 465354000
-
1
tz.transition 1985, 3, :o3, 481078800
-
1
tz.transition 1985, 9, :o2, 496803600
-
1
tz.transition 1986, 3, :o3, 512528400
-
1
tz.transition 1986, 9, :o2, 528253200
-
1
tz.transition 1987, 3, :o3, 543978000
-
1
tz.transition 1987, 9, :o2, 559702800
-
1
tz.transition 1988, 3, :o3, 575427600
-
1
tz.transition 1988, 9, :o2, 591152400
-
1
tz.transition 1989, 3, :o3, 606877200
-
1
tz.transition 1989, 9, :o2, 622602000
-
1
tz.transition 1990, 3, :o3, 638326800
-
1
tz.transition 1990, 9, :o2, 654656400
-
1
tz.transition 1991, 3, :o3, 670381200
-
1
tz.transition 1991, 9, :o2, 686106000
-
1
tz.transition 1992, 3, :o3, 701830800
-
1
tz.transition 1992, 9, :o2, 717555600
-
1
tz.transition 1993, 3, :o3, 733280400
-
1
tz.transition 1993, 9, :o2, 749005200
-
1
tz.transition 1994, 3, :o3, 764730000
-
1
tz.transition 1994, 9, :o2, 780454800
-
1
tz.transition 1995, 3, :o3, 796179600
-
1
tz.transition 1995, 9, :o2, 811904400
-
1
tz.transition 1996, 3, :o3, 828234000
-
1
tz.transition 1996, 10, :o2, 846378000
-
1
tz.transition 1997, 3, :o3, 859683600
-
1
tz.transition 1997, 10, :o2, 877827600
-
1
tz.transition 1998, 3, :o3, 891133200
-
1
tz.transition 1998, 10, :o2, 909277200
-
1
tz.transition 1999, 3, :o3, 922582800
-
1
tz.transition 1999, 10, :o2, 941331600
-
1
tz.transition 2000, 3, :o3, 954032400
-
1
tz.transition 2000, 10, :o2, 972781200
-
1
tz.transition 2001, 3, :o3, 985482000
-
1
tz.transition 2001, 10, :o2, 1004230800
-
1
tz.transition 2002, 3, :o3, 1017536400
-
1
tz.transition 2002, 10, :o2, 1035680400
-
1
tz.transition 2003, 3, :o3, 1048986000
-
1
tz.transition 2003, 10, :o2, 1067130000
-
1
tz.transition 2004, 3, :o3, 1080435600
-
1
tz.transition 2004, 10, :o2, 1099184400
-
1
tz.transition 2005, 3, :o3, 1111885200
-
1
tz.transition 2005, 10, :o2, 1130634000
-
1
tz.transition 2006, 3, :o3, 1143334800
-
1
tz.transition 2006, 10, :o2, 1162083600
-
1
tz.transition 2007, 3, :o3, 1174784400
-
1
tz.transition 2007, 10, :o2, 1193533200
-
1
tz.transition 2008, 3, :o3, 1206838800
-
1
tz.transition 2008, 10, :o2, 1224982800
-
1
tz.transition 2009, 3, :o3, 1238288400
-
1
tz.transition 2009, 10, :o2, 1256432400
-
1
tz.transition 2010, 3, :o3, 1269738000
-
1
tz.transition 2010, 10, :o2, 1288486800
-
1
tz.transition 2011, 3, :o3, 1301187600
-
1
tz.transition 2011, 10, :o2, 1319936400
-
1
tz.transition 2012, 3, :o3, 1332637200
-
1
tz.transition 2012, 10, :o2, 1351386000
-
1
tz.transition 2013, 3, :o3, 1364691600
-
1
tz.transition 2013, 10, :o2, 1382835600
-
1
tz.transition 2014, 3, :o3, 1396141200
-
1
tz.transition 2014, 10, :o2, 1414285200
-
1
tz.transition 2015, 3, :o3, 1427590800
-
1
tz.transition 2015, 10, :o2, 1445734800
-
1
tz.transition 2016, 3, :o3, 1459040400
-
1
tz.transition 2016, 10, :o2, 1477789200
-
1
tz.transition 2017, 3, :o3, 1490490000
-
1
tz.transition 2017, 10, :o2, 1509238800
-
1
tz.transition 2018, 3, :o3, 1521939600
-
1
tz.transition 2018, 10, :o2, 1540688400
-
1
tz.transition 2019, 3, :o3, 1553994000
-
1
tz.transition 2019, 10, :o2, 1572138000
-
1
tz.transition 2020, 3, :o3, 1585443600
-
1
tz.transition 2020, 10, :o2, 1603587600
-
1
tz.transition 2021, 3, :o3, 1616893200
-
1
tz.transition 2021, 10, :o2, 1635642000
-
1
tz.transition 2022, 3, :o3, 1648342800
-
1
tz.transition 2022, 10, :o2, 1667091600
-
1
tz.transition 2023, 3, :o3, 1679792400
-
1
tz.transition 2023, 10, :o2, 1698541200
-
1
tz.transition 2024, 3, :o3, 1711846800
-
1
tz.transition 2024, 10, :o2, 1729990800
-
1
tz.transition 2025, 3, :o3, 1743296400
-
1
tz.transition 2025, 10, :o2, 1761440400
-
1
tz.transition 2026, 3, :o3, 1774746000
-
1
tz.transition 2026, 10, :o2, 1792890000
-
1
tz.transition 2027, 3, :o3, 1806195600
-
1
tz.transition 2027, 10, :o2, 1824944400
-
1
tz.transition 2028, 3, :o3, 1837645200
-
1
tz.transition 2028, 10, :o2, 1856394000
-
1
tz.transition 2029, 3, :o3, 1869094800
-
1
tz.transition 2029, 10, :o2, 1887843600
-
1
tz.transition 2030, 3, :o3, 1901149200
-
1
tz.transition 2030, 10, :o2, 1919293200
-
1
tz.transition 2031, 3, :o3, 1932598800
-
1
tz.transition 2031, 10, :o2, 1950742800
-
1
tz.transition 2032, 3, :o3, 1964048400
-
1
tz.transition 2032, 10, :o2, 1982797200
-
1
tz.transition 2033, 3, :o3, 1995498000
-
1
tz.transition 2033, 10, :o2, 2014246800
-
1
tz.transition 2034, 3, :o3, 2026947600
-
1
tz.transition 2034, 10, :o2, 2045696400
-
1
tz.transition 2035, 3, :o3, 2058397200
-
1
tz.transition 2035, 10, :o2, 2077146000
-
1
tz.transition 2036, 3, :o3, 2090451600
-
1
tz.transition 2036, 10, :o2, 2108595600
-
1
tz.transition 2037, 3, :o3, 2121901200
-
1
tz.transition 2037, 10, :o2, 2140045200
-
1
tz.transition 2038, 3, :o3, 59172253, 24
-
1
tz.transition 2038, 10, :o2, 59177461, 24
-
1
tz.transition 2039, 3, :o3, 59180989, 24
-
1
tz.transition 2039, 10, :o2, 59186197, 24
-
1
tz.transition 2040, 3, :o3, 59189725, 24
-
1
tz.transition 2040, 10, :o2, 59194933, 24
-
1
tz.transition 2041, 3, :o3, 59198629, 24
-
1
tz.transition 2041, 10, :o2, 59203669, 24
-
1
tz.transition 2042, 3, :o3, 59207365, 24
-
1
tz.transition 2042, 10, :o2, 59212405, 24
-
1
tz.transition 2043, 3, :o3, 59216101, 24
-
1
tz.transition 2043, 10, :o2, 59221141, 24
-
1
tz.transition 2044, 3, :o3, 59224837, 24
-
1
tz.transition 2044, 10, :o2, 59230045, 24
-
1
tz.transition 2045, 3, :o3, 59233573, 24
-
1
tz.transition 2045, 10, :o2, 59238781, 24
-
1
tz.transition 2046, 3, :o3, 59242309, 24
-
1
tz.transition 2046, 10, :o2, 59247517, 24
-
1
tz.transition 2047, 3, :o3, 59251213, 24
-
1
tz.transition 2047, 10, :o2, 59256253, 24
-
1
tz.transition 2048, 3, :o3, 59259949, 24
-
1
tz.transition 2048, 10, :o2, 59264989, 24
-
1
tz.transition 2049, 3, :o3, 59268685, 24
-
1
tz.transition 2049, 10, :o2, 59273893, 24
-
1
tz.transition 2050, 3, :o3, 59277421, 24
-
1
tz.transition 2050, 10, :o2, 59282629, 24
-
end
-
end
-
end
-
end
-
end
-
1
module TZInfo
-
1
module Definitions
-
1
module Europe
-
1
module Dublin
-
1
include TimezoneDefinition
-
-
1
timezone 'Europe/Dublin' do |tz|
-
1
tz.offset :o0, -1500, 0, :LMT
-
1
tz.offset :o1, -1521, 0, :DMT
-
1
tz.offset :o2, -1521, 3600, :IST
-
1
tz.offset :o3, 0, 0, :GMT
-
1
tz.offset :o4, 0, 3600, :BST
-
1
tz.offset :o5, 0, 3600, :IST
-
1
tz.offset :o6, 3600, 0, :IST
-
-
1
tz.transition 1880, 8, :o1, 693483701, 288
-
1
tz.transition 1916, 5, :o2, 7747214723, 3200
-
1
tz.transition 1916, 10, :o3, 7747640323, 3200
-
1
tz.transition 1917, 4, :o4, 29055919, 12
-
1
tz.transition 1917, 9, :o3, 29057863, 12
-
1
tz.transition 1918, 3, :o4, 29060119, 12
-
1
tz.transition 1918, 9, :o3, 29062399, 12
-
1
tz.transition 1919, 3, :o4, 29064571, 12
-
1
tz.transition 1919, 9, :o3, 29066767, 12
-
1
tz.transition 1920, 3, :o4, 29068939, 12
-
1
tz.transition 1920, 10, :o3, 29071471, 12
-
1
tz.transition 1921, 4, :o4, 29073391, 12
-
1
tz.transition 1921, 10, :o3, 29075587, 12
-
1
tz.transition 1922, 3, :o5, 29077675, 12
-
1
tz.transition 1922, 10, :o3, 29080027, 12
-
1
tz.transition 1923, 4, :o5, 29082379, 12
-
1
tz.transition 1923, 9, :o3, 29084143, 12
-
1
tz.transition 1924, 4, :o5, 29086663, 12
-
1
tz.transition 1924, 9, :o3, 29088595, 12
-
1
tz.transition 1925, 4, :o5, 29091115, 12
-
1
tz.transition 1925, 10, :o3, 29093131, 12
-
1
tz.transition 1926, 4, :o5, 29095483, 12
-
1
tz.transition 1926, 10, :o3, 29097499, 12
-
1
tz.transition 1927, 4, :o5, 29099767, 12
-
1
tz.transition 1927, 10, :o3, 29101867, 12
-
1
tz.transition 1928, 4, :o5, 29104303, 12
-
1
tz.transition 1928, 10, :o3, 29106319, 12
-
1
tz.transition 1929, 4, :o5, 29108671, 12
-
1
tz.transition 1929, 10, :o3, 29110687, 12
-
1
tz.transition 1930, 4, :o5, 29112955, 12
-
1
tz.transition 1930, 10, :o3, 29115055, 12
-
1
tz.transition 1931, 4, :o5, 29117407, 12
-
1
tz.transition 1931, 10, :o3, 29119423, 12
-
1
tz.transition 1932, 4, :o5, 29121775, 12
-
1
tz.transition 1932, 10, :o3, 29123791, 12
-
1
tz.transition 1933, 4, :o5, 29126059, 12
-
1
tz.transition 1933, 10, :o3, 29128243, 12
-
1
tz.transition 1934, 4, :o5, 29130595, 12
-
1
tz.transition 1934, 10, :o3, 29132611, 12
-
1
tz.transition 1935, 4, :o5, 29134879, 12
-
1
tz.transition 1935, 10, :o3, 29136979, 12
-
1
tz.transition 1936, 4, :o5, 29139331, 12
-
1
tz.transition 1936, 10, :o3, 29141347, 12
-
1
tz.transition 1937, 4, :o5, 29143699, 12
-
1
tz.transition 1937, 10, :o3, 29145715, 12
-
1
tz.transition 1938, 4, :o5, 29147983, 12
-
1
tz.transition 1938, 10, :o3, 29150083, 12
-
1
tz.transition 1939, 4, :o5, 29152435, 12
-
1
tz.transition 1939, 11, :o3, 29155039, 12
-
1
tz.transition 1940, 2, :o5, 29156215, 12
-
1
tz.transition 1946, 10, :o3, 58370389, 24
-
1
tz.transition 1947, 3, :o5, 29187127, 12
-
1
tz.transition 1947, 11, :o3, 58379797, 24
-
1
tz.transition 1948, 4, :o5, 29191915, 12
-
1
tz.transition 1948, 10, :o3, 29194267, 12
-
1
tz.transition 1949, 4, :o5, 29196115, 12
-
1
tz.transition 1949, 10, :o3, 29198635, 12
-
1
tz.transition 1950, 4, :o5, 29200651, 12
-
1
tz.transition 1950, 10, :o3, 29202919, 12
-
1
tz.transition 1951, 4, :o5, 29205019, 12
-
1
tz.transition 1951, 10, :o3, 29207287, 12
-
1
tz.transition 1952, 4, :o5, 29209471, 12
-
1
tz.transition 1952, 10, :o3, 29211739, 12
-
1
tz.transition 1953, 4, :o5, 29213839, 12
-
1
tz.transition 1953, 10, :o3, 29215855, 12
-
1
tz.transition 1954, 4, :o5, 29218123, 12
-
1
tz.transition 1954, 10, :o3, 29220223, 12
-
1
tz.transition 1955, 4, :o5, 29222575, 12
-
1
tz.transition 1955, 10, :o3, 29224591, 12
-
1
tz.transition 1956, 4, :o5, 29227027, 12
-
1
tz.transition 1956, 10, :o3, 29229043, 12
-
1
tz.transition 1957, 4, :o5, 29231311, 12
-
1
tz.transition 1957, 10, :o3, 29233411, 12
-
1
tz.transition 1958, 4, :o5, 29235763, 12
-
1
tz.transition 1958, 10, :o3, 29237779, 12
-
1
tz.transition 1959, 4, :o5, 29240131, 12
-
1
tz.transition 1959, 10, :o3, 29242147, 12
-
1
tz.transition 1960, 4, :o5, 29244415, 12
-
1
tz.transition 1960, 10, :o3, 29246515, 12
-
1
tz.transition 1961, 3, :o5, 29248615, 12
-
1
tz.transition 1961, 10, :o3, 29251219, 12
-
1
tz.transition 1962, 3, :o5, 29252983, 12
-
1
tz.transition 1962, 10, :o3, 29255587, 12
-
1
tz.transition 1963, 3, :o5, 29257435, 12
-
1
tz.transition 1963, 10, :o3, 29259955, 12
-
1
tz.transition 1964, 3, :o5, 29261719, 12
-
1
tz.transition 1964, 10, :o3, 29264323, 12
-
1
tz.transition 1965, 3, :o5, 29266087, 12
-
1
tz.transition 1965, 10, :o3, 29268691, 12
-
1
tz.transition 1966, 3, :o5, 29270455, 12
-
1
tz.transition 1966, 10, :o3, 29273059, 12
-
1
tz.transition 1967, 3, :o5, 29274823, 12
-
1
tz.transition 1967, 10, :o3, 29277511, 12
-
1
tz.transition 1968, 2, :o5, 29278855, 12
-
1
tz.transition 1968, 10, :o6, 58563755, 24
-
1
tz.transition 1971, 10, :o3, 57722400
-
1
tz.transition 1972, 3, :o5, 69818400
-
1
tz.transition 1972, 10, :o3, 89172000
-
1
tz.transition 1973, 3, :o5, 101268000
-
1
tz.transition 1973, 10, :o3, 120621600
-
1
tz.transition 1974, 3, :o5, 132717600
-
1
tz.transition 1974, 10, :o3, 152071200
-
1
tz.transition 1975, 3, :o5, 164167200
-
1
tz.transition 1975, 10, :o3, 183520800
-
1
tz.transition 1976, 3, :o5, 196221600
-
1
tz.transition 1976, 10, :o3, 214970400
-
1
tz.transition 1977, 3, :o5, 227671200
-
1
tz.transition 1977, 10, :o3, 246420000
-
1
tz.transition 1978, 3, :o5, 259120800
-
1
tz.transition 1978, 10, :o3, 278474400
-
1
tz.transition 1979, 3, :o5, 290570400
-
1
tz.transition 1979, 10, :o3, 309924000
-
1
tz.transition 1980, 3, :o5, 322020000
-
1
tz.transition 1980, 10, :o3, 341373600
-
1
tz.transition 1981, 3, :o5, 354675600
-
1
tz.transition 1981, 10, :o3, 372819600
-
1
tz.transition 1982, 3, :o5, 386125200
-
1
tz.transition 1982, 10, :o3, 404269200
-
1
tz.transition 1983, 3, :o5, 417574800
-
1
tz.transition 1983, 10, :o3, 435718800
-
1
tz.transition 1984, 3, :o5, 449024400
-
1
tz.transition 1984, 10, :o3, 467773200
-
1
tz.transition 1985, 3, :o5, 481078800
-
1
tz.transition 1985, 10, :o3, 499222800
-
1
tz.transition 1986, 3, :o5, 512528400
-
1
tz.transition 1986, 10, :o3, 530672400
-
1
tz.transition 1987, 3, :o5, 543978000
-
1
tz.transition 1987, 10, :o3, 562122000
-
1
tz.transition 1988, 3, :o5, 575427600
-
1
tz.transition 1988, 10, :o3, 593571600
-
1
tz.transition 1989, 3, :o5, 606877200
-
1
tz.transition 1989, 10, :o3, 625626000
-
1
tz.transition 1990, 3, :o5, 638326800
-
1
tz.transition 1990, 10, :o3, 657075600
-
1
tz.transition 1991, 3, :o5, 670381200
-
1
tz.transition 1991, 10, :o3, 688525200
-
1
tz.transition 1992, 3, :o5, 701830800
-
1
tz.transition 1992, 10, :o3, 719974800
-
1
tz.transition 1993, 3, :o5, 733280400
-
1
tz.transition 1993, 10, :o3, 751424400
-
1
tz.transition 1994, 3, :o5, 764730000
-
1
tz.transition 1994, 10, :o3, 782874000
-
1
tz.transition 1995, 3, :o5, 796179600
-
1
tz.transition 1995, 10, :o3, 814323600
-
1
tz.transition 1996, 3, :o5, 828234000
-
1
tz.transition 1996, 10, :o3, 846378000
-
1
tz.transition 1997, 3, :o5, 859683600
-
1
tz.transition 1997, 10, :o3, 877827600
-
1
tz.transition 1998, 3, :o5, 891133200
-
1
tz.transition 1998, 10, :o3, 909277200
-
1
tz.transition 1999, 3, :o5, 922582800
-
1
tz.transition 1999, 10, :o3, 941331600
-
1
tz.transition 2000, 3, :o5, 954032400
-
1
tz.transition 2000, 10, :o3, 972781200
-
1
tz.transition 2001, 3, :o5, 985482000
-
1
tz.transition 2001, 10, :o3, 1004230800
-
1
tz.transition 2002, 3, :o5, 1017536400
-
1
tz.transition 2002, 10, :o3, 1035680400
-
1
tz.transition 2003, 3, :o5, 1048986000
-
1
tz.transition 2003, 10, :o3, 1067130000
-
1
tz.transition 2004, 3, :o5, 1080435600
-
1
tz.transition 2004, 10, :o3, 1099184400
-
1
tz.transition 2005, 3, :o5, 1111885200
-
1
tz.transition 2005, 10, :o3, 1130634000
-
1
tz.transition 2006, 3, :o5, 1143334800
-
1
tz.transition 2006, 10, :o3, 1162083600
-
1
tz.transition 2007, 3, :o5, 1174784400
-
1
tz.transition 2007, 10, :o3, 1193533200
-
1
tz.transition 2008, 3, :o5, 1206838800
-
1
tz.transition 2008, 10, :o3, 1224982800
-
1
tz.transition 2009, 3, :o5, 1238288400
-
1
tz.transition 2009, 10, :o3, 1256432400
-
1
tz.transition 2010, 3, :o5, 1269738000
-
1
tz.transition 2010, 10, :o3, 1288486800
-
1
tz.transition 2011, 3, :o5, 1301187600
-
1
tz.transition 2011, 10, :o3, 1319936400
-
1
tz.transition 2012, 3, :o5, 1332637200
-
1
tz.transition 2012, 10, :o3, 1351386000
-
1
tz.transition 2013, 3, :o5, 1364691600
-
1
tz.transition 2013, 10, :o3, 1382835600
-
1
tz.transition 2014, 3, :o5, 1396141200
-
1
tz.transition 2014, 10, :o3, 1414285200
-
1
tz.transition 2015, 3, :o5, 1427590800
-
1
tz.transition 2015, 10, :o3, 1445734800
-
1
tz.transition 2016, 3, :o5, 1459040400
-
1
tz.transition 2016, 10, :o3, 1477789200
-
1
tz.transition 2017, 3, :o5, 1490490000
-
1
tz.transition 2017, 10, :o3, 1509238800
-
1
tz.transition 2018, 3, :o5, 1521939600
-
1
tz.transition 2018, 10, :o3, 1540688400
-
1
tz.transition 2019, 3, :o5, 1553994000
-
1
tz.transition 2019, 10, :o3, 1572138000
-
1
tz.transition 2020, 3, :o5, 1585443600
-
1
tz.transition 2020, 10, :o3, 1603587600
-
1
tz.transition 2021, 3, :o5, 1616893200
-
1
tz.transition 2021, 10, :o3, 1635642000
-
1
tz.transition 2022, 3, :o5, 1648342800
-
1
tz.transition 2022, 10, :o3, 1667091600
-
1
tz.transition 2023, 3, :o5, 1679792400
-
1
tz.transition 2023, 10, :o3, 1698541200
-
1
tz.transition 2024, 3, :o5, 1711846800
-
1
tz.transition 2024, 10, :o3, 1729990800
-
1
tz.transition 2025, 3, :o5, 1743296400
-
1
tz.transition 2025, 10, :o3, 1761440400
-
1
tz.transition 2026, 3, :o5, 1774746000
-
1
tz.transition 2026, 10, :o3, 1792890000
-
1
tz.transition 2027, 3, :o5, 1806195600
-
1
tz.transition 2027, 10, :o3, 1824944400
-
1
tz.transition 2028, 3, :o5, 1837645200
-
1
tz.transition 2028, 10, :o3, 1856394000
-
1
tz.transition 2029, 3, :o5, 1869094800
-
1
tz.transition 2029, 10, :o3, 1887843600
-
1
tz.transition 2030, 3, :o5, 1901149200
-
1
tz.transition 2030, 10, :o3, 1919293200
-
1
tz.transition 2031, 3, :o5, 1932598800
-
1
tz.transition 2031, 10, :o3, 1950742800
-
1
tz.transition 2032, 3, :o5, 1964048400
-
1
tz.transition 2032, 10, :o3, 1982797200
-
1
tz.transition 2033, 3, :o5, 1995498000
-
1
tz.transition 2033, 10, :o3, 2014246800
-
1
tz.transition 2034, 3, :o5, 2026947600
-
1
tz.transition 2034, 10, :o3, 2045696400
-
1
tz.transition 2035, 3, :o5, 2058397200
-
1
tz.transition 2035, 10, :o3, 2077146000
-
1
tz.transition 2036, 3, :o5, 2090451600
-
1
tz.transition 2036, 10, :o3, 2108595600
-
1
tz.transition 2037, 3, :o5, 2121901200
-
1
tz.transition 2037, 10, :o3, 2140045200
-
1
tz.transition 2038, 3, :o5, 59172253, 24
-
1
tz.transition 2038, 10, :o3, 59177461, 24
-
1
tz.transition 2039, 3, :o5, 59180989, 24
-
1
tz.transition 2039, 10, :o3, 59186197, 24
-
1
tz.transition 2040, 3, :o5, 59189725, 24
-
1
tz.transition 2040, 10, :o3, 59194933, 24
-
1
tz.transition 2041, 3, :o5, 59198629, 24
-
1
tz.transition 2041, 10, :o3, 59203669, 24
-
1
tz.transition 2042, 3, :o5, 59207365, 24
-
1
tz.transition 2042, 10, :o3, 59212405, 24
-
1
tz.transition 2043, 3, :o5, 59216101, 24
-
1
tz.transition 2043, 10, :o3, 59221141, 24
-
1
tz.transition 2044, 3, :o5, 59224837, 24
-
1
tz.transition 2044, 10, :o3, 59230045, 24
-
1
tz.transition 2045, 3, :o5, 59233573, 24
-
1
tz.transition 2045, 10, :o3, 59238781, 24
-
1
tz.transition 2046, 3, :o5, 59242309, 24
-
1
tz.transition 2046, 10, :o3, 59247517, 24
-
1
tz.transition 2047, 3, :o5, 59251213, 24
-
1
tz.transition 2047, 10, :o3, 59256253, 24
-
1
tz.transition 2048, 3, :o5, 59259949, 24
-
1
tz.transition 2048, 10, :o3, 59264989, 24
-
1
tz.transition 2049, 3, :o5, 59268685, 24
-
1
tz.transition 2049, 10, :o3, 59273893, 24
-
1
tz.transition 2050, 3, :o5, 59277421, 24
-
1
tz.transition 2050, 10, :o3, 59282629, 24
-
end
-
end
-
end
-
end
-
end
-
1
module TZInfo
-
1
module Definitions
-
1
module Europe
-
1
module Helsinki
-
1
include TimezoneDefinition
-
-
1
timezone 'Europe/Helsinki' do |tz|
-
1
tz.offset :o0, 5992, 0, :LMT
-
1
tz.offset :o1, 5992, 0, :HMT
-
1
tz.offset :o2, 7200, 0, :EET
-
1
tz.offset :o3, 7200, 3600, :EEST
-
-
1
tz.transition 1878, 5, :o1, 25997062651, 10800
-
1
tz.transition 1921, 4, :o2, 26166352651, 10800
-
1
tz.transition 1942, 4, :o3, 29165429, 12
-
1
tz.transition 1942, 10, :o2, 19445083, 8
-
1
tz.transition 1981, 3, :o3, 354672000
-
1
tz.transition 1981, 9, :o2, 370396800
-
1
tz.transition 1982, 3, :o3, 386121600
-
1
tz.transition 1982, 9, :o2, 401846400
-
1
tz.transition 1983, 3, :o3, 417574800
-
1
tz.transition 1983, 9, :o2, 433299600
-
1
tz.transition 1984, 3, :o3, 449024400
-
1
tz.transition 1984, 9, :o2, 465354000
-
1
tz.transition 1985, 3, :o3, 481078800
-
1
tz.transition 1985, 9, :o2, 496803600
-
1
tz.transition 1986, 3, :o3, 512528400
-
1
tz.transition 1986, 9, :o2, 528253200
-
1
tz.transition 1987, 3, :o3, 543978000
-
1
tz.transition 1987, 9, :o2, 559702800
-
1
tz.transition 1988, 3, :o3, 575427600
-
1
tz.transition 1988, 9, :o2, 591152400
-
1
tz.transition 1989, 3, :o3, 606877200
-
1
tz.transition 1989, 9, :o2, 622602000
-
1
tz.transition 1990, 3, :o3, 638326800
-
1
tz.transition 1990, 9, :o2, 654656400
-
1
tz.transition 1991, 3, :o3, 670381200
-
1
tz.transition 1991, 9, :o2, 686106000
-
1
tz.transition 1992, 3, :o3, 701830800
-
1
tz.transition 1992, 9, :o2, 717555600
-
1
tz.transition 1993, 3, :o3, 733280400
-
1
tz.transition 1993, 9, :o2, 749005200
-
1
tz.transition 1994, 3, :o3, 764730000
-
1
tz.transition 1994, 9, :o2, 780454800
-
1
tz.transition 1995, 3, :o3, 796179600
-
1
tz.transition 1995, 9, :o2, 811904400
-
1
tz.transition 1996, 3, :o3, 828234000
-
1
tz.transition 1996, 10, :o2, 846378000
-
1
tz.transition 1997, 3, :o3, 859683600
-
1
tz.transition 1997, 10, :o2, 877827600
-
1
tz.transition 1998, 3, :o3, 891133200
-
1
tz.transition 1998, 10, :o2, 909277200
-
1
tz.transition 1999, 3, :o3, 922582800
-
1
tz.transition 1999, 10, :o2, 941331600
-
1
tz.transition 2000, 3, :o3, 954032400
-
1
tz.transition 2000, 10, :o2, 972781200
-
1
tz.transition 2001, 3, :o3, 985482000
-
1
tz.transition 2001, 10, :o2, 1004230800
-
1
tz.transition 2002, 3, :o3, 1017536400
-
1
tz.transition 2002, 10, :o2, 1035680400
-
1
tz.transition 2003, 3, :o3, 1048986000
-
1
tz.transition 2003, 10, :o2, 1067130000
-
1
tz.transition 2004, 3, :o3, 1080435600
-
1
tz.transition 2004, 10, :o2, 1099184400
-
1
tz.transition 2005, 3, :o3, 1111885200
-
1
tz.transition 2005, 10, :o2, 1130634000
-
1
tz.transition 2006, 3, :o3, 1143334800
-
1
tz.transition 2006, 10, :o2, 1162083600
-
1
tz.transition 2007, 3, :o3, 1174784400
-
1
tz.transition 2007, 10, :o2, 1193533200
-
1
tz.transition 2008, 3, :o3, 1206838800
-
1
tz.transition 2008, 10, :o2, 1224982800
-
1
tz.transition 2009, 3, :o3, 1238288400
-
1
tz.transition 2009, 10, :o2, 1256432400
-
1
tz.transition 2010, 3, :o3, 1269738000
-
1
tz.transition 2010, 10, :o2, 1288486800
-
1
tz.transition 2011, 3, :o3, 1301187600
-
1
tz.transition 2011, 10, :o2, 1319936400
-
1
tz.transition 2012, 3, :o3, 1332637200
-
1
tz.transition 2012, 10, :o2, 1351386000
-
1
tz.transition 2013, 3, :o3, 1364691600
-
1
tz.transition 2013, 10, :o2, 1382835600
-
1
tz.transition 2014, 3, :o3, 1396141200
-
1
tz.transition 2014, 10, :o2, 1414285200
-
1
tz.transition 2015, 3, :o3, 1427590800
-
1
tz.transition 2015, 10, :o2, 1445734800
-
1
tz.transition 2016, 3, :o3, 1459040400
-
1
tz.transition 2016, 10, :o2, 1477789200
-
1
tz.transition 2017, 3, :o3, 1490490000
-
1
tz.transition 2017, 10, :o2, 1509238800
-
1
tz.transition 2018, 3, :o3, 1521939600
-
1
tz.transition 2018, 10, :o2, 1540688400
-
1
tz.transition 2019, 3, :o3, 1553994000
-
1
tz.transition 2019, 10, :o2, 1572138000
-
1
tz.transition 2020, 3, :o3, 1585443600
-
1
tz.transition 2020, 10, :o2, 1603587600
-
1
tz.transition 2021, 3, :o3, 1616893200
-
1
tz.transition 2021, 10, :o2, 1635642000
-
1
tz.transition 2022, 3, :o3, 1648342800
-
1
tz.transition 2022, 10, :o2, 1667091600
-
1
tz.transition 2023, 3, :o3, 1679792400
-
1
tz.transition 2023, 10, :o2, 1698541200
-
1
tz.transition 2024, 3, :o3, 1711846800
-
1
tz.transition 2024, 10, :o2, 1729990800
-
1
tz.transition 2025, 3, :o3, 1743296400
-
1
tz.transition 2025, 10, :o2, 1761440400
-
1
tz.transition 2026, 3, :o3, 1774746000
-
1
tz.transition 2026, 10, :o2, 1792890000
-
1
tz.transition 2027, 3, :o3, 1806195600
-
1
tz.transition 2027, 10, :o2, 1824944400
-
1
tz.transition 2028, 3, :o3, 1837645200
-
1
tz.transition 2028, 10, :o2, 1856394000
-
1
tz.transition 2029, 3, :o3, 1869094800
-
1
tz.transition 2029, 10, :o2, 1887843600
-
1
tz.transition 2030, 3, :o3, 1901149200
-
1
tz.transition 2030, 10, :o2, 1919293200
-
1
tz.transition 2031, 3, :o3, 1932598800
-
1
tz.transition 2031, 10, :o2, 1950742800
-
1
tz.transition 2032, 3, :o3, 1964048400
-
1
tz.transition 2032, 10, :o2, 1982797200
-
1
tz.transition 2033, 3, :o3, 1995498000
-
1
tz.transition 2033, 10, :o2, 2014246800
-
1
tz.transition 2034, 3, :o3, 2026947600
-
1
tz.transition 2034, 10, :o2, 2045696400
-
1
tz.transition 2035, 3, :o3, 2058397200
-
1
tz.transition 2035, 10, :o2, 2077146000
-
1
tz.transition 2036, 3, :o3, 2090451600
-
1
tz.transition 2036, 10, :o2, 2108595600
-
1
tz.transition 2037, 3, :o3, 2121901200
-
1
tz.transition 2037, 10, :o2, 2140045200
-
1
tz.transition 2038, 3, :o3, 59172253, 24
-
1
tz.transition 2038, 10, :o2, 59177461, 24
-
1
tz.transition 2039, 3, :o3, 59180989, 24
-
1
tz.transition 2039, 10, :o2, 59186197, 24
-
1
tz.transition 2040, 3, :o3, 59189725, 24
-
1
tz.transition 2040, 10, :o2, 59194933, 24
-
1
tz.transition 2041, 3, :o3, 59198629, 24
-
1
tz.transition 2041, 10, :o2, 59203669, 24
-
1
tz.transition 2042, 3, :o3, 59207365, 24
-
1
tz.transition 2042, 10, :o2, 59212405, 24
-
1
tz.transition 2043, 3, :o3, 59216101, 24
-
1
tz.transition 2043, 10, :o2, 59221141, 24
-
1
tz.transition 2044, 3, :o3, 59224837, 24
-
1
tz.transition 2044, 10, :o2, 59230045, 24
-
1
tz.transition 2045, 3, :o3, 59233573, 24
-
1
tz.transition 2045, 10, :o2, 59238781, 24
-
1
tz.transition 2046, 3, :o3, 59242309, 24
-
1
tz.transition 2046, 10, :o2, 59247517, 24
-
1
tz.transition 2047, 3, :o3, 59251213, 24
-
1
tz.transition 2047, 10, :o2, 59256253, 24
-
1
tz.transition 2048, 3, :o3, 59259949, 24
-
1
tz.transition 2048, 10, :o2, 59264989, 24
-
1
tz.transition 2049, 3, :o3, 59268685, 24
-
1
tz.transition 2049, 10, :o2, 59273893, 24
-
1
tz.transition 2050, 3, :o3, 59277421, 24
-
1
tz.transition 2050, 10, :o2, 59282629, 24
-
end
-
end
-
end
-
end
-
end
-
1
module TZInfo
-
1
module Definitions
-
1
module Europe
-
1
module Istanbul
-
1
include TimezoneDefinition
-
-
1
timezone 'Europe/Istanbul' do |tz|
-
1
tz.offset :o0, 6952, 0, :LMT
-
1
tz.offset :o1, 7016, 0, :IMT
-
1
tz.offset :o2, 7200, 0, :EET
-
1
tz.offset :o3, 7200, 3600, :EEST
-
1
tz.offset :o4, 10800, 3600, :TRST
-
1
tz.offset :o5, 10800, 0, :TRT
-
-
1
tz.transition 1879, 12, :o1, 26003326531, 10800
-
1
tz.transition 1910, 9, :o2, 26124610523, 10800
-
1
tz.transition 1916, 4, :o3, 29051813, 12
-
1
tz.transition 1916, 9, :o2, 19369099, 8
-
1
tz.transition 1920, 3, :o3, 29068937, 12
-
1
tz.transition 1920, 10, :o2, 19380979, 8
-
1
tz.transition 1921, 4, :o3, 29073389, 12
-
1
tz.transition 1921, 10, :o2, 19383723, 8
-
1
tz.transition 1922, 3, :o3, 29077673, 12
-
1
tz.transition 1922, 10, :o2, 19386683, 8
-
1
tz.transition 1924, 5, :o3, 29087021, 12
-
1
tz.transition 1924, 9, :o2, 19392475, 8
-
1
tz.transition 1925, 4, :o3, 29091257, 12
-
1
tz.transition 1925, 9, :o2, 19395395, 8
-
1
tz.transition 1940, 6, :o3, 29157725, 12
-
1
tz.transition 1940, 10, :o2, 19439259, 8
-
1
tz.transition 1940, 11, :o3, 29159573, 12
-
1
tz.transition 1941, 9, :o2, 19442067, 8
-
1
tz.transition 1942, 3, :o3, 29165405, 12
-
1
tz.transition 1942, 10, :o2, 19445315, 8
-
1
tz.transition 1945, 4, :o3, 29178569, 12
-
1
tz.transition 1945, 10, :o2, 19453891, 8
-
1
tz.transition 1946, 5, :o3, 29183669, 12
-
1
tz.transition 1946, 9, :o2, 19456755, 8
-
1
tz.transition 1947, 4, :o3, 29187545, 12
-
1
tz.transition 1947, 10, :o2, 19459707, 8
-
1
tz.transition 1948, 4, :o3, 29191913, 12
-
1
tz.transition 1948, 10, :o2, 19462619, 8
-
1
tz.transition 1949, 4, :o3, 29196197, 12
-
1
tz.transition 1949, 10, :o2, 19465531, 8
-
1
tz.transition 1950, 4, :o3, 29200685, 12
-
1
tz.transition 1950, 10, :o2, 19468499, 8
-
1
tz.transition 1951, 4, :o3, 29205101, 12
-
1
tz.transition 1951, 10, :o2, 19471419, 8
-
1
tz.transition 1962, 7, :o3, 29254325, 12
-
1
tz.transition 1962, 10, :o2, 19503563, 8
-
1
tz.transition 1964, 5, :o3, 29262365, 12
-
1
tz.transition 1964, 9, :o2, 19509355, 8
-
1
tz.transition 1970, 5, :o3, 10533600
-
1
tz.transition 1970, 10, :o2, 23835600
-
1
tz.transition 1971, 5, :o3, 41983200
-
1
tz.transition 1971, 10, :o2, 55285200
-
1
tz.transition 1972, 5, :o3, 74037600
-
1
tz.transition 1972, 10, :o2, 87339600
-
1
tz.transition 1973, 6, :o3, 107910000
-
1
tz.transition 1973, 11, :o2, 121219200
-
1
tz.transition 1974, 3, :o3, 133920000
-
1
tz.transition 1974, 11, :o2, 152676000
-
1
tz.transition 1975, 3, :o3, 165362400
-
1
tz.transition 1975, 10, :o2, 183502800
-
1
tz.transition 1976, 5, :o3, 202428000
-
1
tz.transition 1976, 10, :o2, 215557200
-
1
tz.transition 1977, 4, :o3, 228866400
-
1
tz.transition 1977, 10, :o2, 245797200
-
1
tz.transition 1978, 4, :o3, 260316000
-
1
tz.transition 1978, 10, :o4, 277246800
-
1
tz.transition 1979, 10, :o5, 308779200
-
1
tz.transition 1980, 4, :o4, 323827200
-
1
tz.transition 1980, 10, :o5, 340228800
-
1
tz.transition 1981, 3, :o4, 354672000
-
1
tz.transition 1981, 10, :o5, 371678400
-
1
tz.transition 1982, 3, :o4, 386121600
-
1
tz.transition 1982, 10, :o5, 403128000
-
1
tz.transition 1983, 7, :o4, 428446800
-
1
tz.transition 1983, 10, :o5, 433886400
-
1
tz.transition 1985, 4, :o3, 482792400
-
1
tz.transition 1985, 9, :o2, 496702800
-
1
tz.transition 1986, 3, :o3, 512524800
-
1
tz.transition 1986, 9, :o2, 528249600
-
1
tz.transition 1987, 3, :o3, 543974400
-
1
tz.transition 1987, 9, :o2, 559699200
-
1
tz.transition 1988, 3, :o3, 575424000
-
1
tz.transition 1988, 9, :o2, 591148800
-
1
tz.transition 1989, 3, :o3, 606873600
-
1
tz.transition 1989, 9, :o2, 622598400
-
1
tz.transition 1990, 3, :o3, 638323200
-
1
tz.transition 1990, 9, :o2, 654652800
-
1
tz.transition 1991, 3, :o3, 670374000
-
1
tz.transition 1991, 9, :o2, 686098800
-
1
tz.transition 1992, 3, :o3, 701823600
-
1
tz.transition 1992, 9, :o2, 717548400
-
1
tz.transition 1993, 3, :o3, 733273200
-
1
tz.transition 1993, 9, :o2, 748998000
-
1
tz.transition 1994, 3, :o3, 764722800
-
1
tz.transition 1994, 9, :o2, 780447600
-
1
tz.transition 1995, 3, :o3, 796172400
-
1
tz.transition 1995, 9, :o2, 811897200
-
1
tz.transition 1996, 3, :o3, 828226800
-
1
tz.transition 1996, 10, :o2, 846370800
-
1
tz.transition 1997, 3, :o3, 859676400
-
1
tz.transition 1997, 10, :o2, 877820400
-
1
tz.transition 1998, 3, :o3, 891126000
-
1
tz.transition 1998, 10, :o2, 909270000
-
1
tz.transition 1999, 3, :o3, 922575600
-
1
tz.transition 1999, 10, :o2, 941324400
-
1
tz.transition 2000, 3, :o3, 954025200
-
1
tz.transition 2000, 10, :o2, 972774000
-
1
tz.transition 2001, 3, :o3, 985474800
-
1
tz.transition 2001, 10, :o2, 1004223600
-
1
tz.transition 2002, 3, :o3, 1017529200
-
1
tz.transition 2002, 10, :o2, 1035673200
-
1
tz.transition 2003, 3, :o3, 1048978800
-
1
tz.transition 2003, 10, :o2, 1067122800
-
1
tz.transition 2004, 3, :o3, 1080428400
-
1
tz.transition 2004, 10, :o2, 1099177200
-
1
tz.transition 2005, 3, :o3, 1111878000
-
1
tz.transition 2005, 10, :o2, 1130626800
-
1
tz.transition 2006, 3, :o3, 1143327600
-
1
tz.transition 2006, 10, :o2, 1162076400
-
1
tz.transition 2007, 3, :o3, 1174784400
-
1
tz.transition 2007, 10, :o2, 1193533200
-
1
tz.transition 2008, 3, :o3, 1206838800
-
1
tz.transition 2008, 10, :o2, 1224982800
-
1
tz.transition 2009, 3, :o3, 1238288400
-
1
tz.transition 2009, 10, :o2, 1256432400
-
1
tz.transition 2010, 3, :o3, 1269738000
-
1
tz.transition 2010, 10, :o2, 1288486800
-
1
tz.transition 2011, 3, :o3, 1301274000
-
1
tz.transition 2011, 10, :o2, 1319936400
-
1
tz.transition 2012, 3, :o3, 1332637200
-
1
tz.transition 2012, 10, :o2, 1351386000
-
1
tz.transition 2013, 3, :o3, 1364691600
-
1
tz.transition 2013, 10, :o2, 1382835600
-
1
tz.transition 2014, 3, :o3, 1396141200
-
1
tz.transition 2014, 10, :o2, 1414285200
-
1
tz.transition 2015, 3, :o3, 1427590800
-
1
tz.transition 2015, 10, :o2, 1445734800
-
1
tz.transition 2016, 3, :o3, 1459040400
-
1
tz.transition 2016, 10, :o2, 1477789200
-
1
tz.transition 2017, 3, :o3, 1490490000
-
1
tz.transition 2017, 10, :o2, 1509238800
-
1
tz.transition 2018, 3, :o3, 1521939600
-
1
tz.transition 2018, 10, :o2, 1540688400
-
1
tz.transition 2019, 3, :o3, 1553994000
-
1
tz.transition 2019, 10, :o2, 1572138000
-
1
tz.transition 2020, 3, :o3, 1585443600
-
1
tz.transition 2020, 10, :o2, 1603587600
-
1
tz.transition 2021, 3, :o3, 1616893200
-
1
tz.transition 2021, 10, :o2, 1635642000
-
1
tz.transition 2022, 3, :o3, 1648342800
-
1
tz.transition 2022, 10, :o2, 1667091600
-
1
tz.transition 2023, 3, :o3, 1679792400
-
1
tz.transition 2023, 10, :o2, 1698541200
-
1
tz.transition 2024, 3, :o3, 1711846800
-
1
tz.transition 2024, 10, :o2, 1729990800
-
1
tz.transition 2025, 3, :o3, 1743296400
-
1
tz.transition 2025, 10, :o2, 1761440400
-
1
tz.transition 2026, 3, :o3, 1774746000
-
1
tz.transition 2026, 10, :o2, 1792890000
-
1
tz.transition 2027, 3, :o3, 1806195600
-
1
tz.transition 2027, 10, :o2, 1824944400
-
1
tz.transition 2028, 3, :o3, 1837645200
-
1
tz.transition 2028, 10, :o2, 1856394000
-
1
tz.transition 2029, 3, :o3, 1869094800
-
1
tz.transition 2029, 10, :o2, 1887843600
-
1
tz.transition 2030, 3, :o3, 1901149200
-
1
tz.transition 2030, 10, :o2, 1919293200
-
1
tz.transition 2031, 3, :o3, 1932598800
-
1
tz.transition 2031, 10, :o2, 1950742800
-
1
tz.transition 2032, 3, :o3, 1964048400
-
1
tz.transition 2032, 10, :o2, 1982797200
-
1
tz.transition 2033, 3, :o3, 1995498000
-
1
tz.transition 2033, 10, :o2, 2014246800
-
1
tz.transition 2034, 3, :o3, 2026947600
-
1
tz.transition 2034, 10, :o2, 2045696400
-
1
tz.transition 2035, 3, :o3, 2058397200
-
1
tz.transition 2035, 10, :o2, 2077146000
-
1
tz.transition 2036, 3, :o3, 2090451600
-
1
tz.transition 2036, 10, :o2, 2108595600
-
1
tz.transition 2037, 3, :o3, 2121901200
-
1
tz.transition 2037, 10, :o2, 2140045200
-
1
tz.transition 2038, 3, :o3, 59172253, 24
-
1
tz.transition 2038, 10, :o2, 59177461, 24
-
1
tz.transition 2039, 3, :o3, 59180989, 24
-
1
tz.transition 2039, 10, :o2, 59186197, 24
-
1
tz.transition 2040, 3, :o3, 59189725, 24
-
1
tz.transition 2040, 10, :o2, 59194933, 24
-
1
tz.transition 2041, 3, :o3, 59198629, 24
-
1
tz.transition 2041, 10, :o2, 59203669, 24
-
1
tz.transition 2042, 3, :o3, 59207365, 24
-
1
tz.transition 2042, 10, :o2, 59212405, 24
-
1
tz.transition 2043, 3, :o3, 59216101, 24
-
1
tz.transition 2043, 10, :o2, 59221141, 24
-
1
tz.transition 2044, 3, :o3, 59224837, 24
-
1
tz.transition 2044, 10, :o2, 59230045, 24
-
1
tz.transition 2045, 3, :o3, 59233573, 24
-
1
tz.transition 2045, 10, :o2, 59238781, 24
-
1
tz.transition 2046, 3, :o3, 59242309, 24
-
1
tz.transition 2046, 10, :o2, 59247517, 24
-
1
tz.transition 2047, 3, :o3, 59251213, 24
-
1
tz.transition 2047, 10, :o2, 59256253, 24
-
1
tz.transition 2048, 3, :o3, 59259949, 24
-
1
tz.transition 2048, 10, :o2, 59264989, 24
-
1
tz.transition 2049, 3, :o3, 59268685, 24
-
1
tz.transition 2049, 10, :o2, 59273893, 24
-
1
tz.transition 2050, 3, :o3, 59277421, 24
-
1
tz.transition 2050, 10, :o2, 59282629, 24
-
end
-
end
-
end
-
end
-
end
-
1
module TZInfo
-
1
module Definitions
-
1
module Europe
-
1
module Kiev
-
1
include TimezoneDefinition
-
-
1
timezone 'Europe/Kiev' do |tz|
-
1
tz.offset :o0, 7324, 0, :LMT
-
1
tz.offset :o1, 7324, 0, :KMT
-
1
tz.offset :o2, 7200, 0, :EET
-
1
tz.offset :o3, 10800, 0, :MSK
-
1
tz.offset :o4, 3600, 3600, :CEST
-
1
tz.offset :o5, 3600, 0, :CET
-
1
tz.offset :o6, 10800, 3600, :MSD
-
1
tz.offset :o7, 7200, 3600, :EEST
-
-
1
tz.transition 1879, 12, :o1, 52006652969, 21600
-
1
tz.transition 1924, 5, :o2, 52356400169, 21600
-
1
tz.transition 1930, 6, :o3, 29113781, 12
-
1
tz.transition 1941, 9, :o4, 19442059, 8
-
1
tz.transition 1942, 11, :o5, 58335973, 24
-
1
tz.transition 1943, 3, :o4, 58339501, 24
-
1
tz.transition 1943, 10, :o5, 58344037, 24
-
1
tz.transition 1943, 11, :o3, 58344827, 24
-
1
tz.transition 1981, 3, :o6, 354920400
-
1
tz.transition 1981, 9, :o3, 370728000
-
1
tz.transition 1982, 3, :o6, 386456400
-
1
tz.transition 1982, 9, :o3, 402264000
-
1
tz.transition 1983, 3, :o6, 417992400
-
1
tz.transition 1983, 9, :o3, 433800000
-
1
tz.transition 1984, 3, :o6, 449614800
-
1
tz.transition 1984, 9, :o3, 465346800
-
1
tz.transition 1985, 3, :o6, 481071600
-
1
tz.transition 1985, 9, :o3, 496796400
-
1
tz.transition 1986, 3, :o6, 512521200
-
1
tz.transition 1986, 9, :o3, 528246000
-
1
tz.transition 1987, 3, :o6, 543970800
-
1
tz.transition 1987, 9, :o3, 559695600
-
1
tz.transition 1988, 3, :o6, 575420400
-
1
tz.transition 1988, 9, :o3, 591145200
-
1
tz.transition 1989, 3, :o6, 606870000
-
1
tz.transition 1989, 9, :o3, 622594800
-
1
tz.transition 1990, 6, :o2, 646786800
-
1
tz.transition 1992, 3, :o7, 701820000
-
1
tz.transition 1992, 9, :o2, 717541200
-
1
tz.transition 1993, 3, :o7, 733269600
-
1
tz.transition 1993, 9, :o2, 748990800
-
1
tz.transition 1994, 3, :o7, 764719200
-
1
tz.transition 1994, 9, :o2, 780440400
-
1
tz.transition 1995, 3, :o7, 796179600
-
1
tz.transition 1995, 9, :o2, 811904400
-
1
tz.transition 1996, 3, :o7, 828234000
-
1
tz.transition 1996, 10, :o2, 846378000
-
1
tz.transition 1997, 3, :o7, 859683600
-
1
tz.transition 1997, 10, :o2, 877827600
-
1
tz.transition 1998, 3, :o7, 891133200
-
1
tz.transition 1998, 10, :o2, 909277200
-
1
tz.transition 1999, 3, :o7, 922582800
-
1
tz.transition 1999, 10, :o2, 941331600
-
1
tz.transition 2000, 3, :o7, 954032400
-
1
tz.transition 2000, 10, :o2, 972781200
-
1
tz.transition 2001, 3, :o7, 985482000
-
1
tz.transition 2001, 10, :o2, 1004230800
-
1
tz.transition 2002, 3, :o7, 1017536400
-
1
tz.transition 2002, 10, :o2, 1035680400
-
1
tz.transition 2003, 3, :o7, 1048986000
-
1
tz.transition 2003, 10, :o2, 1067130000
-
1
tz.transition 2004, 3, :o7, 1080435600
-
1
tz.transition 2004, 10, :o2, 1099184400
-
1
tz.transition 2005, 3, :o7, 1111885200
-
1
tz.transition 2005, 10, :o2, 1130634000
-
1
tz.transition 2006, 3, :o7, 1143334800
-
1
tz.transition 2006, 10, :o2, 1162083600
-
1
tz.transition 2007, 3, :o7, 1174784400
-
1
tz.transition 2007, 10, :o2, 1193533200
-
1
tz.transition 2008, 3, :o7, 1206838800
-
1
tz.transition 2008, 10, :o2, 1224982800
-
1
tz.transition 2009, 3, :o7, 1238288400
-
1
tz.transition 2009, 10, :o2, 1256432400
-
1
tz.transition 2010, 3, :o7, 1269738000
-
1
tz.transition 2010, 10, :o2, 1288486800
-
1
tz.transition 2011, 3, :o7, 1301187600
-
1
tz.transition 2011, 10, :o2, 1319936400
-
1
tz.transition 2012, 3, :o7, 1332637200
-
1
tz.transition 2012, 10, :o2, 1351386000
-
1
tz.transition 2013, 3, :o7, 1364691600
-
1
tz.transition 2013, 10, :o2, 1382835600
-
1
tz.transition 2014, 3, :o7, 1396141200
-
1
tz.transition 2014, 10, :o2, 1414285200
-
1
tz.transition 2015, 3, :o7, 1427590800
-
1
tz.transition 2015, 10, :o2, 1445734800
-
1
tz.transition 2016, 3, :o7, 1459040400
-
1
tz.transition 2016, 10, :o2, 1477789200
-
1
tz.transition 2017, 3, :o7, 1490490000
-
1
tz.transition 2017, 10, :o2, 1509238800
-
1
tz.transition 2018, 3, :o7, 1521939600
-
1
tz.transition 2018, 10, :o2, 1540688400
-
1
tz.transition 2019, 3, :o7, 1553994000
-
1
tz.transition 2019, 10, :o2, 1572138000
-
1
tz.transition 2020, 3, :o7, 1585443600
-
1
tz.transition 2020, 10, :o2, 1603587600
-
1
tz.transition 2021, 3, :o7, 1616893200
-
1
tz.transition 2021, 10, :o2, 1635642000
-
1
tz.transition 2022, 3, :o7, 1648342800
-
1
tz.transition 2022, 10, :o2, 1667091600
-
1
tz.transition 2023, 3, :o7, 1679792400
-
1
tz.transition 2023, 10, :o2, 1698541200
-
1
tz.transition 2024, 3, :o7, 1711846800
-
1
tz.transition 2024, 10, :o2, 1729990800
-
1
tz.transition 2025, 3, :o7, 1743296400
-
1
tz.transition 2025, 10, :o2, 1761440400
-
1
tz.transition 2026, 3, :o7, 1774746000
-
1
tz.transition 2026, 10, :o2, 1792890000
-
1
tz.transition 2027, 3, :o7, 1806195600
-
1
tz.transition 2027, 10, :o2, 1824944400
-
1
tz.transition 2028, 3, :o7, 1837645200
-
1
tz.transition 2028, 10, :o2, 1856394000
-
1
tz.transition 2029, 3, :o7, 1869094800
-
1
tz.transition 2029, 10, :o2, 1887843600
-
1
tz.transition 2030, 3, :o7, 1901149200
-
1
tz.transition 2030, 10, :o2, 1919293200
-
1
tz.transition 2031, 3, :o7, 1932598800
-
1
tz.transition 2031, 10, :o2, 1950742800
-
1
tz.transition 2032, 3, :o7, 1964048400
-
1
tz.transition 2032, 10, :o2, 1982797200
-
1
tz.transition 2033, 3, :o7, 1995498000
-
1
tz.transition 2033, 10, :o2, 2014246800
-
1
tz.transition 2034, 3, :o7, 2026947600
-
1
tz.transition 2034, 10, :o2, 2045696400
-
1
tz.transition 2035, 3, :o7, 2058397200
-
1
tz.transition 2035, 10, :o2, 2077146000
-
1
tz.transition 2036, 3, :o7, 2090451600
-
1
tz.transition 2036, 10, :o2, 2108595600
-
1
tz.transition 2037, 3, :o7, 2121901200
-
1
tz.transition 2037, 10, :o2, 2140045200
-
1
tz.transition 2038, 3, :o7, 59172253, 24
-
1
tz.transition 2038, 10, :o2, 59177461, 24
-
1
tz.transition 2039, 3, :o7, 59180989, 24
-
1
tz.transition 2039, 10, :o2, 59186197, 24
-
1
tz.transition 2040, 3, :o7, 59189725, 24
-
1
tz.transition 2040, 10, :o2, 59194933, 24
-
1
tz.transition 2041, 3, :o7, 59198629, 24
-
1
tz.transition 2041, 10, :o2, 59203669, 24
-
1
tz.transition 2042, 3, :o7, 59207365, 24
-
1
tz.transition 2042, 10, :o2, 59212405, 24
-
1
tz.transition 2043, 3, :o7, 59216101, 24
-
1
tz.transition 2043, 10, :o2, 59221141, 24
-
1
tz.transition 2044, 3, :o7, 59224837, 24
-
1
tz.transition 2044, 10, :o2, 59230045, 24
-
1
tz.transition 2045, 3, :o7, 59233573, 24
-
1
tz.transition 2045, 10, :o2, 59238781, 24
-
1
tz.transition 2046, 3, :o7, 59242309, 24
-
1
tz.transition 2046, 10, :o2, 59247517, 24
-
1
tz.transition 2047, 3, :o7, 59251213, 24
-
1
tz.transition 2047, 10, :o2, 59256253, 24
-
1
tz.transition 2048, 3, :o7, 59259949, 24
-
1
tz.transition 2048, 10, :o2, 59264989, 24
-
1
tz.transition 2049, 3, :o7, 59268685, 24
-
1
tz.transition 2049, 10, :o2, 59273893, 24
-
1
tz.transition 2050, 3, :o7, 59277421, 24
-
1
tz.transition 2050, 10, :o2, 59282629, 24
-
end
-
end
-
end
-
end
-
end
-
1
module TZInfo
-
1
module Definitions
-
1
module Europe
-
1
module Lisbon
-
1
include TimezoneDefinition
-
-
1
timezone 'Europe/Lisbon' do |tz|
-
1
tz.offset :o0, -2192, 0, :LMT
-
1
tz.offset :o1, 0, 0, :WET
-
1
tz.offset :o2, 0, 3600, :WEST
-
1
tz.offset :o3, 0, 7200, :WEMT
-
1
tz.offset :o4, 3600, 0, :CET
-
1
tz.offset :o5, 3600, 3600, :CEST
-
-
1
tz.transition 1912, 1, :o1, 13064773637, 5400
-
1
tz.transition 1916, 6, :o2, 58104779, 24
-
1
tz.transition 1916, 11, :o1, 4842337, 2
-
1
tz.transition 1917, 2, :o2, 58110923, 24
-
1
tz.transition 1917, 10, :o1, 58116395, 24
-
1
tz.transition 1918, 3, :o2, 58119707, 24
-
1
tz.transition 1918, 10, :o1, 58125155, 24
-
1
tz.transition 1919, 2, :o2, 58128443, 24
-
1
tz.transition 1919, 10, :o1, 58133915, 24
-
1
tz.transition 1920, 2, :o2, 58137227, 24
-
1
tz.transition 1920, 10, :o1, 58142699, 24
-
1
tz.transition 1921, 2, :o2, 58145987, 24
-
1
tz.transition 1921, 10, :o1, 58151459, 24
-
1
tz.transition 1924, 4, :o2, 58173419, 24
-
1
tz.transition 1924, 10, :o1, 58177763, 24
-
1
tz.transition 1926, 4, :o2, 58190963, 24
-
1
tz.transition 1926, 10, :o1, 58194995, 24
-
1
tz.transition 1927, 4, :o2, 58199531, 24
-
1
tz.transition 1927, 10, :o1, 58203731, 24
-
1
tz.transition 1928, 4, :o2, 58208435, 24
-
1
tz.transition 1928, 10, :o1, 58212635, 24
-
1
tz.transition 1929, 4, :o2, 58217339, 24
-
1
tz.transition 1929, 10, :o1, 58221371, 24
-
1
tz.transition 1931, 4, :o2, 58234811, 24
-
1
tz.transition 1931, 10, :o1, 58238843, 24
-
1
tz.transition 1932, 4, :o2, 58243211, 24
-
1
tz.transition 1932, 10, :o1, 58247579, 24
-
1
tz.transition 1934, 4, :o2, 58260851, 24
-
1
tz.transition 1934, 10, :o1, 58265219, 24
-
1
tz.transition 1935, 3, :o2, 58269419, 24
-
1
tz.transition 1935, 10, :o1, 58273955, 24
-
1
tz.transition 1936, 4, :o2, 58278659, 24
-
1
tz.transition 1936, 10, :o1, 58282691, 24
-
1
tz.transition 1937, 4, :o2, 58287059, 24
-
1
tz.transition 1937, 10, :o1, 58291427, 24
-
1
tz.transition 1938, 3, :o2, 58295627, 24
-
1
tz.transition 1938, 10, :o1, 58300163, 24
-
1
tz.transition 1939, 4, :o2, 58304867, 24
-
1
tz.transition 1939, 11, :o1, 58310075, 24
-
1
tz.transition 1940, 2, :o2, 58312427, 24
-
1
tz.transition 1940, 10, :o1, 58317803, 24
-
1
tz.transition 1941, 4, :o2, 58322171, 24
-
1
tz.transition 1941, 10, :o1, 58326563, 24
-
1
tz.transition 1942, 3, :o2, 58330403, 24
-
1
tz.transition 1942, 4, :o3, 29165705, 12
-
1
tz.transition 1942, 8, :o2, 29167049, 12
-
1
tz.transition 1942, 10, :o1, 58335779, 24
-
1
tz.transition 1943, 3, :o2, 58339139, 24
-
1
tz.transition 1943, 4, :o3, 29169989, 12
-
1
tz.transition 1943, 8, :o2, 29171585, 12
-
1
tz.transition 1943, 10, :o1, 58344683, 24
-
1
tz.transition 1944, 3, :o2, 58347875, 24
-
1
tz.transition 1944, 4, :o3, 29174441, 12
-
1
tz.transition 1944, 8, :o2, 29175953, 12
-
1
tz.transition 1944, 10, :o1, 58353419, 24
-
1
tz.transition 1945, 3, :o2, 58356611, 24
-
1
tz.transition 1945, 4, :o3, 29178809, 12
-
1
tz.transition 1945, 8, :o2, 29180321, 12
-
1
tz.transition 1945, 10, :o1, 58362155, 24
-
1
tz.transition 1946, 4, :o2, 58366019, 24
-
1
tz.transition 1946, 10, :o1, 58370387, 24
-
1
tz.transition 1947, 4, :o2, 29187379, 12
-
1
tz.transition 1947, 10, :o1, 29189563, 12
-
1
tz.transition 1948, 4, :o2, 29191747, 12
-
1
tz.transition 1948, 10, :o1, 29193931, 12
-
1
tz.transition 1949, 4, :o2, 29196115, 12
-
1
tz.transition 1949, 10, :o1, 29198299, 12
-
1
tz.transition 1951, 4, :o2, 29204851, 12
-
1
tz.transition 1951, 10, :o1, 29207119, 12
-
1
tz.transition 1952, 4, :o2, 29209303, 12
-
1
tz.transition 1952, 10, :o1, 29211487, 12
-
1
tz.transition 1953, 4, :o2, 29213671, 12
-
1
tz.transition 1953, 10, :o1, 29215855, 12
-
1
tz.transition 1954, 4, :o2, 29218039, 12
-
1
tz.transition 1954, 10, :o1, 29220223, 12
-
1
tz.transition 1955, 4, :o2, 29222407, 12
-
1
tz.transition 1955, 10, :o1, 29224591, 12
-
1
tz.transition 1956, 4, :o2, 29226775, 12
-
1
tz.transition 1956, 10, :o1, 29229043, 12
-
1
tz.transition 1957, 4, :o2, 29231227, 12
-
1
tz.transition 1957, 10, :o1, 29233411, 12
-
1
tz.transition 1958, 4, :o2, 29235595, 12
-
1
tz.transition 1958, 10, :o1, 29237779, 12
-
1
tz.transition 1959, 4, :o2, 29239963, 12
-
1
tz.transition 1959, 10, :o1, 29242147, 12
-
1
tz.transition 1960, 4, :o2, 29244331, 12
-
1
tz.transition 1960, 10, :o1, 29246515, 12
-
1
tz.transition 1961, 4, :o2, 29248699, 12
-
1
tz.transition 1961, 10, :o1, 29250883, 12
-
1
tz.transition 1962, 4, :o2, 29253067, 12
-
1
tz.transition 1962, 10, :o1, 29255335, 12
-
1
tz.transition 1963, 4, :o2, 29257519, 12
-
1
tz.transition 1963, 10, :o1, 29259703, 12
-
1
tz.transition 1964, 4, :o2, 29261887, 12
-
1
tz.transition 1964, 10, :o1, 29264071, 12
-
1
tz.transition 1965, 4, :o2, 29266255, 12
-
1
tz.transition 1965, 10, :o1, 29268439, 12
-
1
tz.transition 1966, 4, :o4, 29270623, 12
-
1
tz.transition 1976, 9, :o1, 212544000
-
1
tz.transition 1977, 3, :o2, 228268800
-
1
tz.transition 1977, 9, :o1, 243993600
-
1
tz.transition 1978, 4, :o2, 260323200
-
1
tz.transition 1978, 10, :o1, 276048000
-
1
tz.transition 1979, 4, :o2, 291772800
-
1
tz.transition 1979, 9, :o1, 307501200
-
1
tz.transition 1980, 3, :o2, 323222400
-
1
tz.transition 1980, 9, :o1, 338950800
-
1
tz.transition 1981, 3, :o2, 354675600
-
1
tz.transition 1981, 9, :o1, 370400400
-
1
tz.transition 1982, 3, :o2, 386125200
-
1
tz.transition 1982, 9, :o1, 401850000
-
1
tz.transition 1983, 3, :o2, 417578400
-
1
tz.transition 1983, 9, :o1, 433299600
-
1
tz.transition 1984, 3, :o2, 449024400
-
1
tz.transition 1984, 9, :o1, 465354000
-
1
tz.transition 1985, 3, :o2, 481078800
-
1
tz.transition 1985, 9, :o1, 496803600
-
1
tz.transition 1986, 3, :o2, 512528400
-
1
tz.transition 1986, 9, :o1, 528253200
-
1
tz.transition 1987, 3, :o2, 543978000
-
1
tz.transition 1987, 9, :o1, 559702800
-
1
tz.transition 1988, 3, :o2, 575427600
-
1
tz.transition 1988, 9, :o1, 591152400
-
1
tz.transition 1989, 3, :o2, 606877200
-
1
tz.transition 1989, 9, :o1, 622602000
-
1
tz.transition 1990, 3, :o2, 638326800
-
1
tz.transition 1990, 9, :o1, 654656400
-
1
tz.transition 1991, 3, :o2, 670381200
-
1
tz.transition 1991, 9, :o1, 686106000
-
1
tz.transition 1992, 3, :o2, 701830800
-
1
tz.transition 1992, 9, :o4, 717555600
-
1
tz.transition 1993, 3, :o5, 733280400
-
1
tz.transition 1993, 9, :o4, 749005200
-
1
tz.transition 1994, 3, :o5, 764730000
-
1
tz.transition 1994, 9, :o4, 780454800
-
1
tz.transition 1995, 3, :o5, 796179600
-
1
tz.transition 1995, 9, :o4, 811904400
-
1
tz.transition 1996, 3, :o2, 828234000
-
1
tz.transition 1996, 10, :o1, 846378000
-
1
tz.transition 1997, 3, :o2, 859683600
-
1
tz.transition 1997, 10, :o1, 877827600
-
1
tz.transition 1998, 3, :o2, 891133200
-
1
tz.transition 1998, 10, :o1, 909277200
-
1
tz.transition 1999, 3, :o2, 922582800
-
1
tz.transition 1999, 10, :o1, 941331600
-
1
tz.transition 2000, 3, :o2, 954032400
-
1
tz.transition 2000, 10, :o1, 972781200
-
1
tz.transition 2001, 3, :o2, 985482000
-
1
tz.transition 2001, 10, :o1, 1004230800
-
1
tz.transition 2002, 3, :o2, 1017536400
-
1
tz.transition 2002, 10, :o1, 1035680400
-
1
tz.transition 2003, 3, :o2, 1048986000
-
1
tz.transition 2003, 10, :o1, 1067130000
-
1
tz.transition 2004, 3, :o2, 1080435600
-
1
tz.transition 2004, 10, :o1, 1099184400
-
1
tz.transition 2005, 3, :o2, 1111885200
-
1
tz.transition 2005, 10, :o1, 1130634000
-
1
tz.transition 2006, 3, :o2, 1143334800
-
1
tz.transition 2006, 10, :o1, 1162083600
-
1
tz.transition 2007, 3, :o2, 1174784400
-
1
tz.transition 2007, 10, :o1, 1193533200
-
1
tz.transition 2008, 3, :o2, 1206838800
-
1
tz.transition 2008, 10, :o1, 1224982800
-
1
tz.transition 2009, 3, :o2, 1238288400
-
1
tz.transition 2009, 10, :o1, 1256432400
-
1
tz.transition 2010, 3, :o2, 1269738000
-
1
tz.transition 2010, 10, :o1, 1288486800
-
1
tz.transition 2011, 3, :o2, 1301187600
-
1
tz.transition 2011, 10, :o1, 1319936400
-
1
tz.transition 2012, 3, :o2, 1332637200
-
1
tz.transition 2012, 10, :o1, 1351386000
-
1
tz.transition 2013, 3, :o2, 1364691600
-
1
tz.transition 2013, 10, :o1, 1382835600
-
1
tz.transition 2014, 3, :o2, 1396141200
-
1
tz.transition 2014, 10, :o1, 1414285200
-
1
tz.transition 2015, 3, :o2, 1427590800
-
1
tz.transition 2015, 10, :o1, 1445734800
-
1
tz.transition 2016, 3, :o2, 1459040400
-
1
tz.transition 2016, 10, :o1, 1477789200
-
1
tz.transition 2017, 3, :o2, 1490490000
-
1
tz.transition 2017, 10, :o1, 1509238800
-
1
tz.transition 2018, 3, :o2, 1521939600
-
1
tz.transition 2018, 10, :o1, 1540688400
-
1
tz.transition 2019, 3, :o2, 1553994000
-
1
tz.transition 2019, 10, :o1, 1572138000
-
1
tz.transition 2020, 3, :o2, 1585443600
-
1
tz.transition 2020, 10, :o1, 1603587600
-
1
tz.transition 2021, 3, :o2, 1616893200
-
1
tz.transition 2021, 10, :o1, 1635642000
-
1
tz.transition 2022, 3, :o2, 1648342800
-
1
tz.transition 2022, 10, :o1, 1667091600
-
1
tz.transition 2023, 3, :o2, 1679792400
-
1
tz.transition 2023, 10, :o1, 1698541200
-
1
tz.transition 2024, 3, :o2, 1711846800
-
1
tz.transition 2024, 10, :o1, 1729990800
-
1
tz.transition 2025, 3, :o2, 1743296400
-
1
tz.transition 2025, 10, :o1, 1761440400
-
1
tz.transition 2026, 3, :o2, 1774746000
-
1
tz.transition 2026, 10, :o1, 1792890000
-
1
tz.transition 2027, 3, :o2, 1806195600
-
1
tz.transition 2027, 10, :o1, 1824944400
-
1
tz.transition 2028, 3, :o2, 1837645200
-
1
tz.transition 2028, 10, :o1, 1856394000
-
1
tz.transition 2029, 3, :o2, 1869094800
-
1
tz.transition 2029, 10, :o1, 1887843600
-
1
tz.transition 2030, 3, :o2, 1901149200
-
1
tz.transition 2030, 10, :o1, 1919293200
-
1
tz.transition 2031, 3, :o2, 1932598800
-
1
tz.transition 2031, 10, :o1, 1950742800
-
1
tz.transition 2032, 3, :o2, 1964048400
-
1
tz.transition 2032, 10, :o1, 1982797200
-
1
tz.transition 2033, 3, :o2, 1995498000
-
1
tz.transition 2033, 10, :o1, 2014246800
-
1
tz.transition 2034, 3, :o2, 2026947600
-
1
tz.transition 2034, 10, :o1, 2045696400
-
1
tz.transition 2035, 3, :o2, 2058397200
-
1
tz.transition 2035, 10, :o1, 2077146000
-
1
tz.transition 2036, 3, :o2, 2090451600
-
1
tz.transition 2036, 10, :o1, 2108595600
-
1
tz.transition 2037, 3, :o2, 2121901200
-
1
tz.transition 2037, 10, :o1, 2140045200
-
1
tz.transition 2038, 3, :o2, 59172253, 24
-
1
tz.transition 2038, 10, :o1, 59177461, 24
-
1
tz.transition 2039, 3, :o2, 59180989, 24
-
1
tz.transition 2039, 10, :o1, 59186197, 24
-
1
tz.transition 2040, 3, :o2, 59189725, 24
-
1
tz.transition 2040, 10, :o1, 59194933, 24
-
1
tz.transition 2041, 3, :o2, 59198629, 24
-
1
tz.transition 2041, 10, :o1, 59203669, 24
-
1
tz.transition 2042, 3, :o2, 59207365, 24
-
1
tz.transition 2042, 10, :o1, 59212405, 24
-
1
tz.transition 2043, 3, :o2, 59216101, 24
-
1
tz.transition 2043, 10, :o1, 59221141, 24
-
1
tz.transition 2044, 3, :o2, 59224837, 24
-
1
tz.transition 2044, 10, :o1, 59230045, 24
-
1
tz.transition 2045, 3, :o2, 59233573, 24
-
1
tz.transition 2045, 10, :o1, 59238781, 24
-
1
tz.transition 2046, 3, :o2, 59242309, 24
-
1
tz.transition 2046, 10, :o1, 59247517, 24
-
1
tz.transition 2047, 3, :o2, 59251213, 24
-
1
tz.transition 2047, 10, :o1, 59256253, 24
-
1
tz.transition 2048, 3, :o2, 59259949, 24
-
1
tz.transition 2048, 10, :o1, 59264989, 24
-
1
tz.transition 2049, 3, :o2, 59268685, 24
-
1
tz.transition 2049, 10, :o1, 59273893, 24
-
1
tz.transition 2050, 3, :o2, 59277421, 24
-
1
tz.transition 2050, 10, :o1, 59282629, 24
-
end
-
end
-
end
-
end
-
end
-
1
module TZInfo
-
1
module Definitions
-
1
module Europe
-
1
module Ljubljana
-
1
include TimezoneDefinition
-
-
1
linked_timezone 'Europe/Ljubljana', 'Europe/Belgrade'
-
end
-
end
-
end
-
end
-
1
module TZInfo
-
1
module Definitions
-
1
module Europe
-
1
module London
-
1
include TimezoneDefinition
-
-
1
timezone 'Europe/London' do |tz|
-
1
tz.offset :o0, -75, 0, :LMT
-
1
tz.offset :o1, 0, 0, :GMT
-
1
tz.offset :o2, 0, 3600, :BST
-
1
tz.offset :o3, 0, 7200, :BDST
-
1
tz.offset :o4, 3600, 0, :BST
-
-
1
tz.transition 1847, 12, :o1, 2760187969, 1152
-
1
tz.transition 1916, 5, :o2, 29052055, 12
-
1
tz.transition 1916, 10, :o1, 29053651, 12
-
1
tz.transition 1917, 4, :o2, 29055919, 12
-
1
tz.transition 1917, 9, :o1, 29057863, 12
-
1
tz.transition 1918, 3, :o2, 29060119, 12
-
1
tz.transition 1918, 9, :o1, 29062399, 12
-
1
tz.transition 1919, 3, :o2, 29064571, 12
-
1
tz.transition 1919, 9, :o1, 29066767, 12
-
1
tz.transition 1920, 3, :o2, 29068939, 12
-
1
tz.transition 1920, 10, :o1, 29071471, 12
-
1
tz.transition 1921, 4, :o2, 29073391, 12
-
1
tz.transition 1921, 10, :o1, 29075587, 12
-
1
tz.transition 1922, 3, :o2, 29077675, 12
-
1
tz.transition 1922, 10, :o1, 29080027, 12
-
1
tz.transition 1923, 4, :o2, 29082379, 12
-
1
tz.transition 1923, 9, :o1, 29084143, 12
-
1
tz.transition 1924, 4, :o2, 29086663, 12
-
1
tz.transition 1924, 9, :o1, 29088595, 12
-
1
tz.transition 1925, 4, :o2, 29091115, 12
-
1
tz.transition 1925, 10, :o1, 29093131, 12
-
1
tz.transition 1926, 4, :o2, 29095483, 12
-
1
tz.transition 1926, 10, :o1, 29097499, 12
-
1
tz.transition 1927, 4, :o2, 29099767, 12
-
1
tz.transition 1927, 10, :o1, 29101867, 12
-
1
tz.transition 1928, 4, :o2, 29104303, 12
-
1
tz.transition 1928, 10, :o1, 29106319, 12
-
1
tz.transition 1929, 4, :o2, 29108671, 12
-
1
tz.transition 1929, 10, :o1, 29110687, 12
-
1
tz.transition 1930, 4, :o2, 29112955, 12
-
1
tz.transition 1930, 10, :o1, 29115055, 12
-
1
tz.transition 1931, 4, :o2, 29117407, 12
-
1
tz.transition 1931, 10, :o1, 29119423, 12
-
1
tz.transition 1932, 4, :o2, 29121775, 12
-
1
tz.transition 1932, 10, :o1, 29123791, 12
-
1
tz.transition 1933, 4, :o2, 29126059, 12
-
1
tz.transition 1933, 10, :o1, 29128243, 12
-
1
tz.transition 1934, 4, :o2, 29130595, 12
-
1
tz.transition 1934, 10, :o1, 29132611, 12
-
1
tz.transition 1935, 4, :o2, 29134879, 12
-
1
tz.transition 1935, 10, :o1, 29136979, 12
-
1
tz.transition 1936, 4, :o2, 29139331, 12
-
1
tz.transition 1936, 10, :o1, 29141347, 12
-
1
tz.transition 1937, 4, :o2, 29143699, 12
-
1
tz.transition 1937, 10, :o1, 29145715, 12
-
1
tz.transition 1938, 4, :o2, 29147983, 12
-
1
tz.transition 1938, 10, :o1, 29150083, 12
-
1
tz.transition 1939, 4, :o2, 29152435, 12
-
1
tz.transition 1939, 11, :o1, 29155039, 12
-
1
tz.transition 1940, 2, :o2, 29156215, 12
-
1
tz.transition 1941, 5, :o3, 58322845, 24
-
1
tz.transition 1941, 8, :o2, 58325197, 24
-
1
tz.transition 1942, 4, :o3, 58330909, 24
-
1
tz.transition 1942, 8, :o2, 58333933, 24
-
1
tz.transition 1943, 4, :o3, 58339645, 24
-
1
tz.transition 1943, 8, :o2, 58342837, 24
-
1
tz.transition 1944, 4, :o3, 58348381, 24
-
1
tz.transition 1944, 9, :o2, 58352413, 24
-
1
tz.transition 1945, 4, :o3, 58357141, 24
-
1
tz.transition 1945, 7, :o2, 58359637, 24
-
1
tz.transition 1945, 10, :o1, 29180827, 12
-
1
tz.transition 1946, 4, :o2, 29183095, 12
-
1
tz.transition 1946, 10, :o1, 29185195, 12
-
1
tz.transition 1947, 3, :o2, 29187127, 12
-
1
tz.transition 1947, 4, :o3, 58374925, 24
-
1
tz.transition 1947, 8, :o2, 58377781, 24
-
1
tz.transition 1947, 11, :o1, 29189899, 12
-
1
tz.transition 1948, 3, :o2, 29191495, 12
-
1
tz.transition 1948, 10, :o1, 29194267, 12
-
1
tz.transition 1949, 4, :o2, 29196115, 12
-
1
tz.transition 1949, 10, :o1, 29198635, 12
-
1
tz.transition 1950, 4, :o2, 29200651, 12
-
1
tz.transition 1950, 10, :o1, 29202919, 12
-
1
tz.transition 1951, 4, :o2, 29205019, 12
-
1
tz.transition 1951, 10, :o1, 29207287, 12
-
1
tz.transition 1952, 4, :o2, 29209471, 12
-
1
tz.transition 1952, 10, :o1, 29211739, 12
-
1
tz.transition 1953, 4, :o2, 29213839, 12
-
1
tz.transition 1953, 10, :o1, 29215855, 12
-
1
tz.transition 1954, 4, :o2, 29218123, 12
-
1
tz.transition 1954, 10, :o1, 29220223, 12
-
1
tz.transition 1955, 4, :o2, 29222575, 12
-
1
tz.transition 1955, 10, :o1, 29224591, 12
-
1
tz.transition 1956, 4, :o2, 29227027, 12
-
1
tz.transition 1956, 10, :o1, 29229043, 12
-
1
tz.transition 1957, 4, :o2, 29231311, 12
-
1
tz.transition 1957, 10, :o1, 29233411, 12
-
1
tz.transition 1958, 4, :o2, 29235763, 12
-
1
tz.transition 1958, 10, :o1, 29237779, 12
-
1
tz.transition 1959, 4, :o2, 29240131, 12
-
1
tz.transition 1959, 10, :o1, 29242147, 12
-
1
tz.transition 1960, 4, :o2, 29244415, 12
-
1
tz.transition 1960, 10, :o1, 29246515, 12
-
1
tz.transition 1961, 3, :o2, 29248615, 12
-
1
tz.transition 1961, 10, :o1, 29251219, 12
-
1
tz.transition 1962, 3, :o2, 29252983, 12
-
1
tz.transition 1962, 10, :o1, 29255587, 12
-
1
tz.transition 1963, 3, :o2, 29257435, 12
-
1
tz.transition 1963, 10, :o1, 29259955, 12
-
1
tz.transition 1964, 3, :o2, 29261719, 12
-
1
tz.transition 1964, 10, :o1, 29264323, 12
-
1
tz.transition 1965, 3, :o2, 29266087, 12
-
1
tz.transition 1965, 10, :o1, 29268691, 12
-
1
tz.transition 1966, 3, :o2, 29270455, 12
-
1
tz.transition 1966, 10, :o1, 29273059, 12
-
1
tz.transition 1967, 3, :o2, 29274823, 12
-
1
tz.transition 1967, 10, :o1, 29277511, 12
-
1
tz.transition 1968, 2, :o2, 29278855, 12
-
1
tz.transition 1968, 10, :o4, 58563755, 24
-
1
tz.transition 1971, 10, :o1, 57722400
-
1
tz.transition 1972, 3, :o2, 69818400
-
1
tz.transition 1972, 10, :o1, 89172000
-
1
tz.transition 1973, 3, :o2, 101268000
-
1
tz.transition 1973, 10, :o1, 120621600
-
1
tz.transition 1974, 3, :o2, 132717600
-
1
tz.transition 1974, 10, :o1, 152071200
-
1
tz.transition 1975, 3, :o2, 164167200
-
1
tz.transition 1975, 10, :o1, 183520800
-
1
tz.transition 1976, 3, :o2, 196221600
-
1
tz.transition 1976, 10, :o1, 214970400
-
1
tz.transition 1977, 3, :o2, 227671200
-
1
tz.transition 1977, 10, :o1, 246420000
-
1
tz.transition 1978, 3, :o2, 259120800
-
1
tz.transition 1978, 10, :o1, 278474400
-
1
tz.transition 1979, 3, :o2, 290570400
-
1
tz.transition 1979, 10, :o1, 309924000
-
1
tz.transition 1980, 3, :o2, 322020000
-
1
tz.transition 1980, 10, :o1, 341373600
-
1
tz.transition 1981, 3, :o2, 354675600
-
1
tz.transition 1981, 10, :o1, 372819600
-
1
tz.transition 1982, 3, :o2, 386125200
-
1
tz.transition 1982, 10, :o1, 404269200
-
1
tz.transition 1983, 3, :o2, 417574800
-
1
tz.transition 1983, 10, :o1, 435718800
-
1
tz.transition 1984, 3, :o2, 449024400
-
1
tz.transition 1984, 10, :o1, 467773200
-
1
tz.transition 1985, 3, :o2, 481078800
-
1
tz.transition 1985, 10, :o1, 499222800
-
1
tz.transition 1986, 3, :o2, 512528400
-
1
tz.transition 1986, 10, :o1, 530672400
-
1
tz.transition 1987, 3, :o2, 543978000
-
1
tz.transition 1987, 10, :o1, 562122000
-
1
tz.transition 1988, 3, :o2, 575427600
-
1
tz.transition 1988, 10, :o1, 593571600
-
1
tz.transition 1989, 3, :o2, 606877200
-
1
tz.transition 1989, 10, :o1, 625626000
-
1
tz.transition 1990, 3, :o2, 638326800
-
1
tz.transition 1990, 10, :o1, 657075600
-
1
tz.transition 1991, 3, :o2, 670381200
-
1
tz.transition 1991, 10, :o1, 688525200
-
1
tz.transition 1992, 3, :o2, 701830800
-
1
tz.transition 1992, 10, :o1, 719974800
-
1
tz.transition 1993, 3, :o2, 733280400
-
1
tz.transition 1993, 10, :o1, 751424400
-
1
tz.transition 1994, 3, :o2, 764730000
-
1
tz.transition 1994, 10, :o1, 782874000
-
1
tz.transition 1995, 3, :o2, 796179600
-
1
tz.transition 1995, 10, :o1, 814323600
-
1
tz.transition 1996, 3, :o2, 828234000
-
1
tz.transition 1996, 10, :o1, 846378000
-
1
tz.transition 1997, 3, :o2, 859683600
-
1
tz.transition 1997, 10, :o1, 877827600
-
1
tz.transition 1998, 3, :o2, 891133200
-
1
tz.transition 1998, 10, :o1, 909277200
-
1
tz.transition 1999, 3, :o2, 922582800
-
1
tz.transition 1999, 10, :o1, 941331600
-
1
tz.transition 2000, 3, :o2, 954032400
-
1
tz.transition 2000, 10, :o1, 972781200
-
1
tz.transition 2001, 3, :o2, 985482000
-
1
tz.transition 2001, 10, :o1, 1004230800
-
1
tz.transition 2002, 3, :o2, 1017536400
-
1
tz.transition 2002, 10, :o1, 1035680400
-
1
tz.transition 2003, 3, :o2, 1048986000
-
1
tz.transition 2003, 10, :o1, 1067130000
-
1
tz.transition 2004, 3, :o2, 1080435600
-
1
tz.transition 2004, 10, :o1, 1099184400
-
1
tz.transition 2005, 3, :o2, 1111885200
-
1
tz.transition 2005, 10, :o1, 1130634000
-
1
tz.transition 2006, 3, :o2, 1143334800
-
1
tz.transition 2006, 10, :o1, 1162083600
-
1
tz.transition 2007, 3, :o2, 1174784400
-
1
tz.transition 2007, 10, :o1, 1193533200
-
1
tz.transition 2008, 3, :o2, 1206838800
-
1
tz.transition 2008, 10, :o1, 1224982800
-
1
tz.transition 2009, 3, :o2, 1238288400
-
1
tz.transition 2009, 10, :o1, 1256432400
-
1
tz.transition 2010, 3, :o2, 1269738000
-
1
tz.transition 2010, 10, :o1, 1288486800
-
1
tz.transition 2011, 3, :o2, 1301187600
-
1
tz.transition 2011, 10, :o1, 1319936400
-
1
tz.transition 2012, 3, :o2, 1332637200
-
1
tz.transition 2012, 10, :o1, 1351386000
-
1
tz.transition 2013, 3, :o2, 1364691600
-
1
tz.transition 2013, 10, :o1, 1382835600
-
1
tz.transition 2014, 3, :o2, 1396141200
-
1
tz.transition 2014, 10, :o1, 1414285200
-
1
tz.transition 2015, 3, :o2, 1427590800
-
1
tz.transition 2015, 10, :o1, 1445734800
-
1
tz.transition 2016, 3, :o2, 1459040400
-
1
tz.transition 2016, 10, :o1, 1477789200
-
1
tz.transition 2017, 3, :o2, 1490490000
-
1
tz.transition 2017, 10, :o1, 1509238800
-
1
tz.transition 2018, 3, :o2, 1521939600
-
1
tz.transition 2018, 10, :o1, 1540688400
-
1
tz.transition 2019, 3, :o2, 1553994000
-
1
tz.transition 2019, 10, :o1, 1572138000
-
1
tz.transition 2020, 3, :o2, 1585443600
-
1
tz.transition 2020, 10, :o1, 1603587600
-
1
tz.transition 2021, 3, :o2, 1616893200
-
1
tz.transition 2021, 10, :o1, 1635642000
-
1
tz.transition 2022, 3, :o2, 1648342800
-
1
tz.transition 2022, 10, :o1, 1667091600
-
1
tz.transition 2023, 3, :o2, 1679792400
-
1
tz.transition 2023, 10, :o1, 1698541200
-
1
tz.transition 2024, 3, :o2, 1711846800
-
1
tz.transition 2024, 10, :o1, 1729990800
-
1
tz.transition 2025, 3, :o2, 1743296400
-
1
tz.transition 2025, 10, :o1, 1761440400
-
1
tz.transition 2026, 3, :o2, 1774746000
-
1
tz.transition 2026, 10, :o1, 1792890000
-
1
tz.transition 2027, 3, :o2, 1806195600
-
1
tz.transition 2027, 10, :o1, 1824944400
-
1
tz.transition 2028, 3, :o2, 1837645200
-
1
tz.transition 2028, 10, :o1, 1856394000
-
1
tz.transition 2029, 3, :o2, 1869094800
-
1
tz.transition 2029, 10, :o1, 1887843600
-
1
tz.transition 2030, 3, :o2, 1901149200
-
1
tz.transition 2030, 10, :o1, 1919293200
-
1
tz.transition 2031, 3, :o2, 1932598800
-
1
tz.transition 2031, 10, :o1, 1950742800
-
1
tz.transition 2032, 3, :o2, 1964048400
-
1
tz.transition 2032, 10, :o1, 1982797200
-
1
tz.transition 2033, 3, :o2, 1995498000
-
1
tz.transition 2033, 10, :o1, 2014246800
-
1
tz.transition 2034, 3, :o2, 2026947600
-
1
tz.transition 2034, 10, :o1, 2045696400
-
1
tz.transition 2035, 3, :o2, 2058397200
-
1
tz.transition 2035, 10, :o1, 2077146000
-
1
tz.transition 2036, 3, :o2, 2090451600
-
1
tz.transition 2036, 10, :o1, 2108595600
-
1
tz.transition 2037, 3, :o2, 2121901200
-
1
tz.transition 2037, 10, :o1, 2140045200
-
1
tz.transition 2038, 3, :o2, 59172253, 24
-
1
tz.transition 2038, 10, :o1, 59177461, 24
-
1
tz.transition 2039, 3, :o2, 59180989, 24
-
1
tz.transition 2039, 10, :o1, 59186197, 24
-
1
tz.transition 2040, 3, :o2, 59189725, 24
-
1
tz.transition 2040, 10, :o1, 59194933, 24
-
1
tz.transition 2041, 3, :o2, 59198629, 24
-
1
tz.transition 2041, 10, :o1, 59203669, 24
-
1
tz.transition 2042, 3, :o2, 59207365, 24
-
1
tz.transition 2042, 10, :o1, 59212405, 24
-
1
tz.transition 2043, 3, :o2, 59216101, 24
-
1
tz.transition 2043, 10, :o1, 59221141, 24
-
1
tz.transition 2044, 3, :o2, 59224837, 24
-
1
tz.transition 2044, 10, :o1, 59230045, 24
-
1
tz.transition 2045, 3, :o2, 59233573, 24
-
1
tz.transition 2045, 10, :o1, 59238781, 24
-
1
tz.transition 2046, 3, :o2, 59242309, 24
-
1
tz.transition 2046, 10, :o1, 59247517, 24
-
1
tz.transition 2047, 3, :o2, 59251213, 24
-
1
tz.transition 2047, 10, :o1, 59256253, 24
-
1
tz.transition 2048, 3, :o2, 59259949, 24
-
1
tz.transition 2048, 10, :o1, 59264989, 24
-
1
tz.transition 2049, 3, :o2, 59268685, 24
-
1
tz.transition 2049, 10, :o1, 59273893, 24
-
1
tz.transition 2050, 3, :o2, 59277421, 24
-
1
tz.transition 2050, 10, :o1, 59282629, 24
-
end
-
end
-
end
-
end
-
end
-
1
module TZInfo
-
1
module Definitions
-
1
module Europe
-
1
module Madrid
-
1
include TimezoneDefinition
-
-
1
timezone 'Europe/Madrid' do |tz|
-
1
tz.offset :o0, -884, 0, :LMT
-
1
tz.offset :o1, 0, 0, :WET
-
1
tz.offset :o2, 0, 3600, :WEST
-
1
tz.offset :o3, 0, 7200, :WEMT
-
1
tz.offset :o4, 3600, 0, :CET
-
1
tz.offset :o5, 3600, 3600, :CEST
-
-
1
tz.transition 1901, 1, :o1, 52172327021, 21600
-
1
tz.transition 1917, 5, :o2, 58112507, 24
-
1
tz.transition 1917, 10, :o1, 58116203, 24
-
1
tz.transition 1918, 4, :o2, 58120787, 24
-
1
tz.transition 1918, 10, :o1, 58124963, 24
-
1
tz.transition 1919, 4, :o2, 58129307, 24
-
1
tz.transition 1919, 10, :o1, 58133723, 24
-
1
tz.transition 1924, 4, :o2, 58173419, 24
-
1
tz.transition 1924, 10, :o1, 58177523, 24
-
1
tz.transition 1926, 4, :o2, 58190963, 24
-
1
tz.transition 1926, 10, :o1, 58194995, 24
-
1
tz.transition 1927, 4, :o2, 58199531, 24
-
1
tz.transition 1927, 10, :o1, 58203731, 24
-
1
tz.transition 1928, 4, :o2, 58208435, 24
-
1
tz.transition 1928, 10, :o1, 58212635, 24
-
1
tz.transition 1929, 4, :o2, 58217339, 24
-
1
tz.transition 1929, 10, :o1, 58221371, 24
-
1
tz.transition 1937, 5, :o2, 58288235, 24
-
1
tz.transition 1937, 10, :o1, 58291427, 24
-
1
tz.transition 1938, 3, :o2, 58295531, 24
-
1
tz.transition 1938, 10, :o1, 58300163, 24
-
1
tz.transition 1939, 4, :o2, 58304867, 24
-
1
tz.transition 1939, 10, :o1, 58309067, 24
-
1
tz.transition 1940, 3, :o2, 58312931, 24
-
1
tz.transition 1942, 5, :o3, 29165789, 12
-
1
tz.transition 1942, 9, :o2, 29167253, 12
-
1
tz.transition 1943, 4, :o3, 29169989, 12
-
1
tz.transition 1943, 10, :o2, 29172017, 12
-
1
tz.transition 1944, 4, :o3, 29174357, 12
-
1
tz.transition 1944, 10, :o2, 29176493, 12
-
1
tz.transition 1945, 4, :o3, 29178725, 12
-
1
tz.transition 1945, 9, :o2, 58361483, 24
-
1
tz.transition 1946, 4, :o3, 29183093, 12
-
1
tz.transition 1946, 9, :o4, 29185121, 12
-
1
tz.transition 1949, 4, :o5, 29196449, 12
-
1
tz.transition 1949, 9, :o4, 58396547, 24
-
1
tz.transition 1974, 4, :o5, 135122400
-
1
tz.transition 1974, 10, :o4, 150246000
-
1
tz.transition 1975, 4, :o5, 167176800
-
1
tz.transition 1975, 10, :o4, 181695600
-
1
tz.transition 1976, 3, :o5, 196812000
-
1
tz.transition 1976, 9, :o4, 212540400
-
1
tz.transition 1977, 4, :o5, 228866400
-
1
tz.transition 1977, 9, :o4, 243990000
-
1
tz.transition 1978, 4, :o5, 260402400
-
1
tz.transition 1978, 9, :o4, 276044400
-
1
tz.transition 1979, 4, :o5, 291776400
-
1
tz.transition 1979, 9, :o4, 307501200
-
1
tz.transition 1980, 4, :o5, 323830800
-
1
tz.transition 1980, 9, :o4, 338950800
-
1
tz.transition 1981, 3, :o5, 354675600
-
1
tz.transition 1981, 9, :o4, 370400400
-
1
tz.transition 1982, 3, :o5, 386125200
-
1
tz.transition 1982, 9, :o4, 401850000
-
1
tz.transition 1983, 3, :o5, 417574800
-
1
tz.transition 1983, 9, :o4, 433299600
-
1
tz.transition 1984, 3, :o5, 449024400
-
1
tz.transition 1984, 9, :o4, 465354000
-
1
tz.transition 1985, 3, :o5, 481078800
-
1
tz.transition 1985, 9, :o4, 496803600
-
1
tz.transition 1986, 3, :o5, 512528400
-
1
tz.transition 1986, 9, :o4, 528253200
-
1
tz.transition 1987, 3, :o5, 543978000
-
1
tz.transition 1987, 9, :o4, 559702800
-
1
tz.transition 1988, 3, :o5, 575427600
-
1
tz.transition 1988, 9, :o4, 591152400
-
1
tz.transition 1989, 3, :o5, 606877200
-
1
tz.transition 1989, 9, :o4, 622602000
-
1
tz.transition 1990, 3, :o5, 638326800
-
1
tz.transition 1990, 9, :o4, 654656400
-
1
tz.transition 1991, 3, :o5, 670381200
-
1
tz.transition 1991, 9, :o4, 686106000
-
1
tz.transition 1992, 3, :o5, 701830800
-
1
tz.transition 1992, 9, :o4, 717555600
-
1
tz.transition 1993, 3, :o5, 733280400
-
1
tz.transition 1993, 9, :o4, 749005200
-
1
tz.transition 1994, 3, :o5, 764730000
-
1
tz.transition 1994, 9, :o4, 780454800
-
1
tz.transition 1995, 3, :o5, 796179600
-
1
tz.transition 1995, 9, :o4, 811904400
-
1
tz.transition 1996, 3, :o5, 828234000
-
1
tz.transition 1996, 10, :o4, 846378000
-
1
tz.transition 1997, 3, :o5, 859683600
-
1
tz.transition 1997, 10, :o4, 877827600
-
1
tz.transition 1998, 3, :o5, 891133200
-
1
tz.transition 1998, 10, :o4, 909277200
-
1
tz.transition 1999, 3, :o5, 922582800
-
1
tz.transition 1999, 10, :o4, 941331600
-
1
tz.transition 2000, 3, :o5, 954032400
-
1
tz.transition 2000, 10, :o4, 972781200
-
1
tz.transition 2001, 3, :o5, 985482000
-
1
tz.transition 2001, 10, :o4, 1004230800
-
1
tz.transition 2002, 3, :o5, 1017536400
-
1
tz.transition 2002, 10, :o4, 1035680400
-
1
tz.transition 2003, 3, :o5, 1048986000
-
1
tz.transition 2003, 10, :o4, 1067130000
-
1
tz.transition 2004, 3, :o5, 1080435600
-
1
tz.transition 2004, 10, :o4, 1099184400
-
1
tz.transition 2005, 3, :o5, 1111885200
-
1
tz.transition 2005, 10, :o4, 1130634000
-
1
tz.transition 2006, 3, :o5, 1143334800
-
1
tz.transition 2006, 10, :o4, 1162083600
-
1
tz.transition 2007, 3, :o5, 1174784400
-
1
tz.transition 2007, 10, :o4, 1193533200
-
1
tz.transition 2008, 3, :o5, 1206838800
-
1
tz.transition 2008, 10, :o4, 1224982800
-
1
tz.transition 2009, 3, :o5, 1238288400
-
1
tz.transition 2009, 10, :o4, 1256432400
-
1
tz.transition 2010, 3, :o5, 1269738000
-
1
tz.transition 2010, 10, :o4, 1288486800
-
1
tz.transition 2011, 3, :o5, 1301187600
-
1
tz.transition 2011, 10, :o4, 1319936400
-
1
tz.transition 2012, 3, :o5, 1332637200
-
1
tz.transition 2012, 10, :o4, 1351386000
-
1
tz.transition 2013, 3, :o5, 1364691600
-
1
tz.transition 2013, 10, :o4, 1382835600
-
1
tz.transition 2014, 3, :o5, 1396141200
-
1
tz.transition 2014, 10, :o4, 1414285200
-
1
tz.transition 2015, 3, :o5, 1427590800
-
1
tz.transition 2015, 10, :o4, 1445734800
-
1
tz.transition 2016, 3, :o5, 1459040400
-
1
tz.transition 2016, 10, :o4, 1477789200
-
1
tz.transition 2017, 3, :o5, 1490490000
-
1
tz.transition 2017, 10, :o4, 1509238800
-
1
tz.transition 2018, 3, :o5, 1521939600
-
1
tz.transition 2018, 10, :o4, 1540688400
-
1
tz.transition 2019, 3, :o5, 1553994000
-
1
tz.transition 2019, 10, :o4, 1572138000
-
1
tz.transition 2020, 3, :o5, 1585443600
-
1
tz.transition 2020, 10, :o4, 1603587600
-
1
tz.transition 2021, 3, :o5, 1616893200
-
1
tz.transition 2021, 10, :o4, 1635642000
-
1
tz.transition 2022, 3, :o5, 1648342800
-
1
tz.transition 2022, 10, :o4, 1667091600
-
1
tz.transition 2023, 3, :o5, 1679792400
-
1
tz.transition 2023, 10, :o4, 1698541200
-
1
tz.transition 2024, 3, :o5, 1711846800
-
1
tz.transition 2024, 10, :o4, 1729990800
-
1
tz.transition 2025, 3, :o5, 1743296400
-
1
tz.transition 2025, 10, :o4, 1761440400
-
1
tz.transition 2026, 3, :o5, 1774746000
-
1
tz.transition 2026, 10, :o4, 1792890000
-
1
tz.transition 2027, 3, :o5, 1806195600
-
1
tz.transition 2027, 10, :o4, 1824944400
-
1
tz.transition 2028, 3, :o5, 1837645200
-
1
tz.transition 2028, 10, :o4, 1856394000
-
1
tz.transition 2029, 3, :o5, 1869094800
-
1
tz.transition 2029, 10, :o4, 1887843600
-
1
tz.transition 2030, 3, :o5, 1901149200
-
1
tz.transition 2030, 10, :o4, 1919293200
-
1
tz.transition 2031, 3, :o5, 1932598800
-
1
tz.transition 2031, 10, :o4, 1950742800
-
1
tz.transition 2032, 3, :o5, 1964048400
-
1
tz.transition 2032, 10, :o4, 1982797200
-
1
tz.transition 2033, 3, :o5, 1995498000
-
1
tz.transition 2033, 10, :o4, 2014246800
-
1
tz.transition 2034, 3, :o5, 2026947600
-
1
tz.transition 2034, 10, :o4, 2045696400
-
1
tz.transition 2035, 3, :o5, 2058397200
-
1
tz.transition 2035, 10, :o4, 2077146000
-
1
tz.transition 2036, 3, :o5, 2090451600
-
1
tz.transition 2036, 10, :o4, 2108595600
-
1
tz.transition 2037, 3, :o5, 2121901200
-
1
tz.transition 2037, 10, :o4, 2140045200
-
1
tz.transition 2038, 3, :o5, 59172253, 24
-
1
tz.transition 2038, 10, :o4, 59177461, 24
-
1
tz.transition 2039, 3, :o5, 59180989, 24
-
1
tz.transition 2039, 10, :o4, 59186197, 24
-
1
tz.transition 2040, 3, :o5, 59189725, 24
-
1
tz.transition 2040, 10, :o4, 59194933, 24
-
1
tz.transition 2041, 3, :o5, 59198629, 24
-
1
tz.transition 2041, 10, :o4, 59203669, 24
-
1
tz.transition 2042, 3, :o5, 59207365, 24
-
1
tz.transition 2042, 10, :o4, 59212405, 24
-
1
tz.transition 2043, 3, :o5, 59216101, 24
-
1
tz.transition 2043, 10, :o4, 59221141, 24
-
1
tz.transition 2044, 3, :o5, 59224837, 24
-
1
tz.transition 2044, 10, :o4, 59230045, 24
-
1
tz.transition 2045, 3, :o5, 59233573, 24
-
1
tz.transition 2045, 10, :o4, 59238781, 24
-
1
tz.transition 2046, 3, :o5, 59242309, 24
-
1
tz.transition 2046, 10, :o4, 59247517, 24
-
1
tz.transition 2047, 3, :o5, 59251213, 24
-
1
tz.transition 2047, 10, :o4, 59256253, 24
-
1
tz.transition 2048, 3, :o5, 59259949, 24
-
1
tz.transition 2048, 10, :o4, 59264989, 24
-
1
tz.transition 2049, 3, :o5, 59268685, 24
-
1
tz.transition 2049, 10, :o4, 59273893, 24
-
1
tz.transition 2050, 3, :o5, 59277421, 24
-
1
tz.transition 2050, 10, :o4, 59282629, 24
-
end
-
end
-
end
-
end
-
end
-
1
module TZInfo
-
1
module Definitions
-
1
module Europe
-
1
module Minsk
-
1
include TimezoneDefinition
-
-
1
timezone 'Europe/Minsk' do |tz|
-
1
tz.offset :o0, 6616, 0, :LMT
-
1
tz.offset :o1, 6600, 0, :MMT
-
1
tz.offset :o2, 7200, 0, :EET
-
1
tz.offset :o3, 10800, 0, :MSK
-
1
tz.offset :o4, 3600, 3600, :CEST
-
1
tz.offset :o5, 3600, 0, :CET
-
1
tz.offset :o6, 10800, 3600, :MSD
-
1
tz.offset :o7, 7200, 3600, :EEST
-
1
tz.offset :o8, 10800, 0, :FET
-
-
1
tz.transition 1879, 12, :o1, 26003326573, 10800
-
1
tz.transition 1924, 5, :o2, 349042669, 144
-
1
tz.transition 1930, 6, :o3, 29113781, 12
-
1
tz.transition 1941, 6, :o4, 19441387, 8
-
1
tz.transition 1942, 11, :o5, 58335973, 24
-
1
tz.transition 1943, 3, :o4, 58339501, 24
-
1
tz.transition 1943, 10, :o5, 58344037, 24
-
1
tz.transition 1944, 4, :o4, 58348405, 24
-
1
tz.transition 1944, 7, :o3, 29175293, 12
-
1
tz.transition 1981, 3, :o6, 354920400
-
1
tz.transition 1981, 9, :o3, 370728000
-
1
tz.transition 1982, 3, :o6, 386456400
-
1
tz.transition 1982, 9, :o3, 402264000
-
1
tz.transition 1983, 3, :o6, 417992400
-
1
tz.transition 1983, 9, :o3, 433800000
-
1
tz.transition 1984, 3, :o6, 449614800
-
1
tz.transition 1984, 9, :o3, 465346800
-
1
tz.transition 1985, 3, :o6, 481071600
-
1
tz.transition 1985, 9, :o3, 496796400
-
1
tz.transition 1986, 3, :o6, 512521200
-
1
tz.transition 1986, 9, :o3, 528246000
-
1
tz.transition 1987, 3, :o6, 543970800
-
1
tz.transition 1987, 9, :o3, 559695600
-
1
tz.transition 1988, 3, :o6, 575420400
-
1
tz.transition 1988, 9, :o3, 591145200
-
1
tz.transition 1989, 3, :o6, 606870000
-
1
tz.transition 1989, 9, :o3, 622594800
-
1
tz.transition 1991, 3, :o7, 670374000
-
1
tz.transition 1991, 9, :o2, 686102400
-
1
tz.transition 1992, 3, :o7, 701820000
-
1
tz.transition 1992, 9, :o2, 717544800
-
1
tz.transition 1993, 3, :o7, 733276800
-
1
tz.transition 1993, 9, :o2, 749001600
-
1
tz.transition 1994, 3, :o7, 764726400
-
1
tz.transition 1994, 9, :o2, 780451200
-
1
tz.transition 1995, 3, :o7, 796176000
-
1
tz.transition 1995, 9, :o2, 811900800
-
1
tz.transition 1996, 3, :o7, 828230400
-
1
tz.transition 1996, 10, :o2, 846374400
-
1
tz.transition 1997, 3, :o7, 859680000
-
1
tz.transition 1997, 10, :o2, 877824000
-
1
tz.transition 1998, 3, :o7, 891129600
-
1
tz.transition 1998, 10, :o2, 909273600
-
1
tz.transition 1999, 3, :o7, 922579200
-
1
tz.transition 1999, 10, :o2, 941328000
-
1
tz.transition 2000, 3, :o7, 954028800
-
1
tz.transition 2000, 10, :o2, 972777600
-
1
tz.transition 2001, 3, :o7, 985478400
-
1
tz.transition 2001, 10, :o2, 1004227200
-
1
tz.transition 2002, 3, :o7, 1017532800
-
1
tz.transition 2002, 10, :o2, 1035676800
-
1
tz.transition 2003, 3, :o7, 1048982400
-
1
tz.transition 2003, 10, :o2, 1067126400
-
1
tz.transition 2004, 3, :o7, 1080432000
-
1
tz.transition 2004, 10, :o2, 1099180800
-
1
tz.transition 2005, 3, :o7, 1111881600
-
1
tz.transition 2005, 10, :o2, 1130630400
-
1
tz.transition 2006, 3, :o7, 1143331200
-
1
tz.transition 2006, 10, :o2, 1162080000
-
1
tz.transition 2007, 3, :o7, 1174780800
-
1
tz.transition 2007, 10, :o2, 1193529600
-
1
tz.transition 2008, 3, :o7, 1206835200
-
1
tz.transition 2008, 10, :o2, 1224979200
-
1
tz.transition 2009, 3, :o7, 1238284800
-
1
tz.transition 2009, 10, :o2, 1256428800
-
1
tz.transition 2010, 3, :o7, 1269734400
-
1
tz.transition 2010, 10, :o2, 1288483200
-
1
tz.transition 2011, 3, :o8, 1301184000
-
end
-
end
-
end
-
end
-
end
-
1
module TZInfo
-
1
module Definitions
-
1
module Europe
-
1
module Moscow
-
1
include TimezoneDefinition
-
-
1
timezone 'Europe/Moscow' do |tz|
-
1
tz.offset :o0, 9020, 0, :LMT
-
1
tz.offset :o1, 9000, 0, :MMT
-
1
tz.offset :o2, 9048, 0, :MMT
-
1
tz.offset :o3, 9048, 3600, :MST
-
1
tz.offset :o4, 9048, 7200, :MDST
-
1
tz.offset :o5, 10800, 3600, :MSD
-
1
tz.offset :o6, 10800, 0, :MSK
-
1
tz.offset :o7, 10800, 7200, :MSD
-
1
tz.offset :o8, 7200, 0, :EET
-
1
tz.offset :o9, 7200, 3600, :EEST
-
1
tz.offset :o10, 14400, 0, :MSK
-
-
1
tz.transition 1879, 12, :o1, 10401330509, 4320
-
1
tz.transition 1916, 7, :o2, 116210275, 48
-
1
tz.transition 1917, 7, :o3, 8717080873, 3600
-
1
tz.transition 1917, 12, :o2, 8717725273, 3600
-
1
tz.transition 1918, 5, :o4, 8718283123, 3600
-
1
tz.transition 1918, 9, :o3, 8718668473, 3600
-
1
tz.transition 1919, 5, :o4, 8719597123, 3600
-
1
tz.transition 1919, 6, :o5, 8719705423, 3600
-
1
tz.transition 1919, 8, :o6, 7266559, 3
-
1
tz.transition 1921, 2, :o5, 7268206, 3
-
1
tz.transition 1921, 3, :o7, 58146463, 24
-
1
tz.transition 1921, 8, :o5, 58150399, 24
-
1
tz.transition 1921, 9, :o6, 7268890, 3
-
1
tz.transition 1922, 9, :o8, 19386627, 8
-
1
tz.transition 1930, 6, :o6, 29113781, 12
-
1
tz.transition 1981, 3, :o5, 354920400
-
1
tz.transition 1981, 9, :o6, 370728000
-
1
tz.transition 1982, 3, :o5, 386456400
-
1
tz.transition 1982, 9, :o6, 402264000
-
1
tz.transition 1983, 3, :o5, 417992400
-
1
tz.transition 1983, 9, :o6, 433800000
-
1
tz.transition 1984, 3, :o5, 449614800
-
1
tz.transition 1984, 9, :o6, 465346800
-
1
tz.transition 1985, 3, :o5, 481071600
-
1
tz.transition 1985, 9, :o6, 496796400
-
1
tz.transition 1986, 3, :o5, 512521200
-
1
tz.transition 1986, 9, :o6, 528246000
-
1
tz.transition 1987, 3, :o5, 543970800
-
1
tz.transition 1987, 9, :o6, 559695600
-
1
tz.transition 1988, 3, :o5, 575420400
-
1
tz.transition 1988, 9, :o6, 591145200
-
1
tz.transition 1989, 3, :o5, 606870000
-
1
tz.transition 1989, 9, :o6, 622594800
-
1
tz.transition 1990, 3, :o5, 638319600
-
1
tz.transition 1990, 9, :o6, 654649200
-
1
tz.transition 1991, 3, :o9, 670374000
-
1
tz.transition 1991, 9, :o8, 686102400
-
1
tz.transition 1992, 1, :o6, 695779200
-
1
tz.transition 1992, 3, :o5, 701812800
-
1
tz.transition 1992, 9, :o6, 717534000
-
1
tz.transition 1993, 3, :o5, 733273200
-
1
tz.transition 1993, 9, :o6, 748998000
-
1
tz.transition 1994, 3, :o5, 764722800
-
1
tz.transition 1994, 9, :o6, 780447600
-
1
tz.transition 1995, 3, :o5, 796172400
-
1
tz.transition 1995, 9, :o6, 811897200
-
1
tz.transition 1996, 3, :o5, 828226800
-
1
tz.transition 1996, 10, :o6, 846370800
-
1
tz.transition 1997, 3, :o5, 859676400
-
1
tz.transition 1997, 10, :o6, 877820400
-
1
tz.transition 1998, 3, :o5, 891126000
-
1
tz.transition 1998, 10, :o6, 909270000
-
1
tz.transition 1999, 3, :o5, 922575600
-
1
tz.transition 1999, 10, :o6, 941324400
-
1
tz.transition 2000, 3, :o5, 954025200
-
1
tz.transition 2000, 10, :o6, 972774000
-
1
tz.transition 2001, 3, :o5, 985474800
-
1
tz.transition 2001, 10, :o6, 1004223600
-
1
tz.transition 2002, 3, :o5, 1017529200
-
1
tz.transition 2002, 10, :o6, 1035673200
-
1
tz.transition 2003, 3, :o5, 1048978800
-
1
tz.transition 2003, 10, :o6, 1067122800
-
1
tz.transition 2004, 3, :o5, 1080428400
-
1
tz.transition 2004, 10, :o6, 1099177200
-
1
tz.transition 2005, 3, :o5, 1111878000
-
1
tz.transition 2005, 10, :o6, 1130626800
-
1
tz.transition 2006, 3, :o5, 1143327600
-
1
tz.transition 2006, 10, :o6, 1162076400
-
1
tz.transition 2007, 3, :o5, 1174777200
-
1
tz.transition 2007, 10, :o6, 1193526000
-
1
tz.transition 2008, 3, :o5, 1206831600
-
1
tz.transition 2008, 10, :o6, 1224975600
-
1
tz.transition 2009, 3, :o5, 1238281200
-
1
tz.transition 2009, 10, :o6, 1256425200
-
1
tz.transition 2010, 3, :o5, 1269730800
-
1
tz.transition 2010, 10, :o6, 1288479600
-
1
tz.transition 2011, 3, :o10, 1301180400
-
end
-
end
-
end
-
end
-
end
-
1
module TZInfo
-
1
module Definitions
-
1
module Europe
-
1
module Paris
-
1
include TimezoneDefinition
-
-
1
timezone 'Europe/Paris' do |tz|
-
1
tz.offset :o0, 561, 0, :LMT
-
1
tz.offset :o1, 561, 0, :PMT
-
1
tz.offset :o2, 0, 0, :WET
-
1
tz.offset :o3, 0, 3600, :WEST
-
1
tz.offset :o4, 3600, 3600, :CEST
-
1
tz.offset :o5, 3600, 0, :CET
-
1
tz.offset :o6, 0, 7200, :WEMT
-
-
1
tz.transition 1891, 3, :o1, 69460027033, 28800
-
1
tz.transition 1911, 3, :o2, 69670267033, 28800
-
1
tz.transition 1916, 6, :o3, 58104707, 24
-
1
tz.transition 1916, 10, :o2, 58107323, 24
-
1
tz.transition 1917, 3, :o3, 58111499, 24
-
1
tz.transition 1917, 10, :o2, 58116227, 24
-
1
tz.transition 1918, 3, :o3, 58119899, 24
-
1
tz.transition 1918, 10, :o2, 58124963, 24
-
1
tz.transition 1919, 3, :o3, 58128467, 24
-
1
tz.transition 1919, 10, :o2, 58133699, 24
-
1
tz.transition 1920, 2, :o3, 58136867, 24
-
1
tz.transition 1920, 10, :o2, 58142915, 24
-
1
tz.transition 1921, 3, :o3, 58146323, 24
-
1
tz.transition 1921, 10, :o2, 58151723, 24
-
1
tz.transition 1922, 3, :o3, 58155347, 24
-
1
tz.transition 1922, 10, :o2, 58160051, 24
-
1
tz.transition 1923, 5, :o3, 58165595, 24
-
1
tz.transition 1923, 10, :o2, 58168787, 24
-
1
tz.transition 1924, 3, :o3, 58172987, 24
-
1
tz.transition 1924, 10, :o2, 58177523, 24
-
1
tz.transition 1925, 4, :o3, 58181891, 24
-
1
tz.transition 1925, 10, :o2, 58186259, 24
-
1
tz.transition 1926, 4, :o3, 58190963, 24
-
1
tz.transition 1926, 10, :o2, 58194995, 24
-
1
tz.transition 1927, 4, :o3, 58199531, 24
-
1
tz.transition 1927, 10, :o2, 58203731, 24
-
1
tz.transition 1928, 4, :o3, 58208435, 24
-
1
tz.transition 1928, 10, :o2, 58212635, 24
-
1
tz.transition 1929, 4, :o3, 58217339, 24
-
1
tz.transition 1929, 10, :o2, 58221371, 24
-
1
tz.transition 1930, 4, :o3, 58225907, 24
-
1
tz.transition 1930, 10, :o2, 58230107, 24
-
1
tz.transition 1931, 4, :o3, 58234811, 24
-
1
tz.transition 1931, 10, :o2, 58238843, 24
-
1
tz.transition 1932, 4, :o3, 58243211, 24
-
1
tz.transition 1932, 10, :o2, 58247579, 24
-
1
tz.transition 1933, 3, :o3, 58251779, 24
-
1
tz.transition 1933, 10, :o2, 58256483, 24
-
1
tz.transition 1934, 4, :o3, 58260851, 24
-
1
tz.transition 1934, 10, :o2, 58265219, 24
-
1
tz.transition 1935, 3, :o3, 58269419, 24
-
1
tz.transition 1935, 10, :o2, 58273955, 24
-
1
tz.transition 1936, 4, :o3, 58278659, 24
-
1
tz.transition 1936, 10, :o2, 58282691, 24
-
1
tz.transition 1937, 4, :o3, 58287059, 24
-
1
tz.transition 1937, 10, :o2, 58291427, 24
-
1
tz.transition 1938, 3, :o3, 58295627, 24
-
1
tz.transition 1938, 10, :o2, 58300163, 24
-
1
tz.transition 1939, 4, :o3, 58304867, 24
-
1
tz.transition 1939, 11, :o2, 58310075, 24
-
1
tz.transition 1940, 2, :o3, 29156215, 12
-
1
tz.transition 1940, 6, :o4, 29157545, 12
-
1
tz.transition 1942, 11, :o5, 58335973, 24
-
1
tz.transition 1943, 3, :o4, 58339501, 24
-
1
tz.transition 1943, 10, :o5, 58344037, 24
-
1
tz.transition 1944, 4, :o4, 58348405, 24
-
1
tz.transition 1944, 8, :o6, 29175929, 12
-
1
tz.transition 1944, 10, :o3, 58352915, 24
-
1
tz.transition 1945, 4, :o6, 58357141, 24
-
1
tz.transition 1945, 9, :o5, 58361149, 24
-
1
tz.transition 1976, 3, :o4, 196819200
-
1
tz.transition 1976, 9, :o5, 212540400
-
1
tz.transition 1977, 4, :o4, 228877200
-
1
tz.transition 1977, 9, :o5, 243997200
-
1
tz.transition 1978, 4, :o4, 260326800
-
1
tz.transition 1978, 10, :o5, 276051600
-
1
tz.transition 1979, 4, :o4, 291776400
-
1
tz.transition 1979, 9, :o5, 307501200
-
1
tz.transition 1980, 4, :o4, 323830800
-
1
tz.transition 1980, 9, :o5, 338950800
-
1
tz.transition 1981, 3, :o4, 354675600
-
1
tz.transition 1981, 9, :o5, 370400400
-
1
tz.transition 1982, 3, :o4, 386125200
-
1
tz.transition 1982, 9, :o5, 401850000
-
1
tz.transition 1983, 3, :o4, 417574800
-
1
tz.transition 1983, 9, :o5, 433299600
-
1
tz.transition 1984, 3, :o4, 449024400
-
1
tz.transition 1984, 9, :o5, 465354000
-
1
tz.transition 1985, 3, :o4, 481078800
-
1
tz.transition 1985, 9, :o5, 496803600
-
1
tz.transition 1986, 3, :o4, 512528400
-
1
tz.transition 1986, 9, :o5, 528253200
-
1
tz.transition 1987, 3, :o4, 543978000
-
1
tz.transition 1987, 9, :o5, 559702800
-
1
tz.transition 1988, 3, :o4, 575427600
-
1
tz.transition 1988, 9, :o5, 591152400
-
1
tz.transition 1989, 3, :o4, 606877200
-
1
tz.transition 1989, 9, :o5, 622602000
-
1
tz.transition 1990, 3, :o4, 638326800
-
1
tz.transition 1990, 9, :o5, 654656400
-
1
tz.transition 1991, 3, :o4, 670381200
-
1
tz.transition 1991, 9, :o5, 686106000
-
1
tz.transition 1992, 3, :o4, 701830800
-
1
tz.transition 1992, 9, :o5, 717555600
-
1
tz.transition 1993, 3, :o4, 733280400
-
1
tz.transition 1993, 9, :o5, 749005200
-
1
tz.transition 1994, 3, :o4, 764730000
-
1
tz.transition 1994, 9, :o5, 780454800
-
1
tz.transition 1995, 3, :o4, 796179600
-
1
tz.transition 1995, 9, :o5, 811904400
-
1
tz.transition 1996, 3, :o4, 828234000
-
1
tz.transition 1996, 10, :o5, 846378000
-
1
tz.transition 1997, 3, :o4, 859683600
-
1
tz.transition 1997, 10, :o5, 877827600
-
1
tz.transition 1998, 3, :o4, 891133200
-
1
tz.transition 1998, 10, :o5, 909277200
-
1
tz.transition 1999, 3, :o4, 922582800
-
1
tz.transition 1999, 10, :o5, 941331600
-
1
tz.transition 2000, 3, :o4, 954032400
-
1
tz.transition 2000, 10, :o5, 972781200
-
1
tz.transition 2001, 3, :o4, 985482000
-
1
tz.transition 2001, 10, :o5, 1004230800
-
1
tz.transition 2002, 3, :o4, 1017536400
-
1
tz.transition 2002, 10, :o5, 1035680400
-
1
tz.transition 2003, 3, :o4, 1048986000
-
1
tz.transition 2003, 10, :o5, 1067130000
-
1
tz.transition 2004, 3, :o4, 1080435600
-
1
tz.transition 2004, 10, :o5, 1099184400
-
1
tz.transition 2005, 3, :o4, 1111885200
-
1
tz.transition 2005, 10, :o5, 1130634000
-
1
tz.transition 2006, 3, :o4, 1143334800
-
1
tz.transition 2006, 10, :o5, 1162083600
-
1
tz.transition 2007, 3, :o4, 1174784400
-
1
tz.transition 2007, 10, :o5, 1193533200
-
1
tz.transition 2008, 3, :o4, 1206838800
-
1
tz.transition 2008, 10, :o5, 1224982800
-
1
tz.transition 2009, 3, :o4, 1238288400
-
1
tz.transition 2009, 10, :o5, 1256432400
-
1
tz.transition 2010, 3, :o4, 1269738000
-
1
tz.transition 2010, 10, :o5, 1288486800
-
1
tz.transition 2011, 3, :o4, 1301187600
-
1
tz.transition 2011, 10, :o5, 1319936400
-
1
tz.transition 2012, 3, :o4, 1332637200
-
1
tz.transition 2012, 10, :o5, 1351386000
-
1
tz.transition 2013, 3, :o4, 1364691600
-
1
tz.transition 2013, 10, :o5, 1382835600
-
1
tz.transition 2014, 3, :o4, 1396141200
-
1
tz.transition 2014, 10, :o5, 1414285200
-
1
tz.transition 2015, 3, :o4, 1427590800
-
1
tz.transition 2015, 10, :o5, 1445734800
-
1
tz.transition 2016, 3, :o4, 1459040400
-
1
tz.transition 2016, 10, :o5, 1477789200
-
1
tz.transition 2017, 3, :o4, 1490490000
-
1
tz.transition 2017, 10, :o5, 1509238800
-
1
tz.transition 2018, 3, :o4, 1521939600
-
1
tz.transition 2018, 10, :o5, 1540688400
-
1
tz.transition 2019, 3, :o4, 1553994000
-
1
tz.transition 2019, 10, :o5, 1572138000
-
1
tz.transition 2020, 3, :o4, 1585443600
-
1
tz.transition 2020, 10, :o5, 1603587600
-
1
tz.transition 2021, 3, :o4, 1616893200
-
1
tz.transition 2021, 10, :o5, 1635642000
-
1
tz.transition 2022, 3, :o4, 1648342800
-
1
tz.transition 2022, 10, :o5, 1667091600
-
1
tz.transition 2023, 3, :o4, 1679792400
-
1
tz.transition 2023, 10, :o5, 1698541200
-
1
tz.transition 2024, 3, :o4, 1711846800
-
1
tz.transition 2024, 10, :o5, 1729990800
-
1
tz.transition 2025, 3, :o4, 1743296400
-
1
tz.transition 2025, 10, :o5, 1761440400
-
1
tz.transition 2026, 3, :o4, 1774746000
-
1
tz.transition 2026, 10, :o5, 1792890000
-
1
tz.transition 2027, 3, :o4, 1806195600
-
1
tz.transition 2027, 10, :o5, 1824944400
-
1
tz.transition 2028, 3, :o4, 1837645200
-
1
tz.transition 2028, 10, :o5, 1856394000
-
1
tz.transition 2029, 3, :o4, 1869094800
-
1
tz.transition 2029, 10, :o5, 1887843600
-
1
tz.transition 2030, 3, :o4, 1901149200
-
1
tz.transition 2030, 10, :o5, 1919293200
-
1
tz.transition 2031, 3, :o4, 1932598800
-
1
tz.transition 2031, 10, :o5, 1950742800
-
1
tz.transition 2032, 3, :o4, 1964048400
-
1
tz.transition 2032, 10, :o5, 1982797200
-
1
tz.transition 2033, 3, :o4, 1995498000
-
1
tz.transition 2033, 10, :o5, 2014246800
-
1
tz.transition 2034, 3, :o4, 2026947600
-
1
tz.transition 2034, 10, :o5, 2045696400
-
1
tz.transition 2035, 3, :o4, 2058397200
-
1
tz.transition 2035, 10, :o5, 2077146000
-
1
tz.transition 2036, 3, :o4, 2090451600
-
1
tz.transition 2036, 10, :o5, 2108595600
-
1
tz.transition 2037, 3, :o4, 2121901200
-
1
tz.transition 2037, 10, :o5, 2140045200
-
1
tz.transition 2038, 3, :o4, 59172253, 24
-
1
tz.transition 2038, 10, :o5, 59177461, 24
-
1
tz.transition 2039, 3, :o4, 59180989, 24
-
1
tz.transition 2039, 10, :o5, 59186197, 24
-
1
tz.transition 2040, 3, :o4, 59189725, 24
-
1
tz.transition 2040, 10, :o5, 59194933, 24
-
1
tz.transition 2041, 3, :o4, 59198629, 24
-
1
tz.transition 2041, 10, :o5, 59203669, 24
-
1
tz.transition 2042, 3, :o4, 59207365, 24
-
1
tz.transition 2042, 10, :o5, 59212405, 24
-
1
tz.transition 2043, 3, :o4, 59216101, 24
-
1
tz.transition 2043, 10, :o5, 59221141, 24
-
1
tz.transition 2044, 3, :o4, 59224837, 24
-
1
tz.transition 2044, 10, :o5, 59230045, 24
-
1
tz.transition 2045, 3, :o4, 59233573, 24
-
1
tz.transition 2045, 10, :o5, 59238781, 24
-
1
tz.transition 2046, 3, :o4, 59242309, 24
-
1
tz.transition 2046, 10, :o5, 59247517, 24
-
1
tz.transition 2047, 3, :o4, 59251213, 24
-
1
tz.transition 2047, 10, :o5, 59256253, 24
-
1
tz.transition 2048, 3, :o4, 59259949, 24
-
1
tz.transition 2048, 10, :o5, 59264989, 24
-
1
tz.transition 2049, 3, :o4, 59268685, 24
-
1
tz.transition 2049, 10, :o5, 59273893, 24
-
1
tz.transition 2050, 3, :o4, 59277421, 24
-
1
tz.transition 2050, 10, :o5, 59282629, 24
-
end
-
end
-
end
-
end
-
end
-
1
module TZInfo
-
1
module Definitions
-
1
module Europe
-
1
module Prague
-
1
include TimezoneDefinition
-
-
1
timezone 'Europe/Prague' do |tz|
-
1
tz.offset :o0, 3464, 0, :LMT
-
1
tz.offset :o1, 3464, 0, :PMT
-
1
tz.offset :o2, 3600, 0, :CET
-
1
tz.offset :o3, 3600, 3600, :CEST
-
-
1
tz.transition 1849, 12, :o1, 25884991367, 10800
-
1
tz.transition 1891, 9, :o2, 26049669767, 10800
-
1
tz.transition 1916, 4, :o3, 29051813, 12
-
1
tz.transition 1916, 9, :o2, 58107299, 24
-
1
tz.transition 1917, 4, :o3, 58112029, 24
-
1
tz.transition 1917, 9, :o2, 58115725, 24
-
1
tz.transition 1918, 4, :o3, 58120765, 24
-
1
tz.transition 1918, 9, :o2, 58124461, 24
-
1
tz.transition 1940, 4, :o3, 58313293, 24
-
1
tz.transition 1942, 11, :o2, 58335973, 24
-
1
tz.transition 1943, 3, :o3, 58339501, 24
-
1
tz.transition 1943, 10, :o2, 58344037, 24
-
1
tz.transition 1944, 4, :o3, 58348405, 24
-
1
tz.transition 1944, 9, :o2, 58352413, 24
-
1
tz.transition 1945, 4, :o3, 58357285, 24
-
1
tz.transition 1945, 11, :o2, 58362661, 24
-
1
tz.transition 1946, 5, :o3, 58366717, 24
-
1
tz.transition 1946, 10, :o2, 58370389, 24
-
1
tz.transition 1947, 4, :o3, 58375093, 24
-
1
tz.transition 1947, 10, :o2, 58379125, 24
-
1
tz.transition 1948, 4, :o3, 58383829, 24
-
1
tz.transition 1948, 10, :o2, 58387861, 24
-
1
tz.transition 1949, 4, :o3, 58392373, 24
-
1
tz.transition 1949, 10, :o2, 58396597, 24
-
1
tz.transition 1979, 4, :o3, 291776400
-
1
tz.transition 1979, 9, :o2, 307501200
-
1
tz.transition 1980, 4, :o3, 323830800
-
1
tz.transition 1980, 9, :o2, 338950800
-
1
tz.transition 1981, 3, :o3, 354675600
-
1
tz.transition 1981, 9, :o2, 370400400
-
1
tz.transition 1982, 3, :o3, 386125200
-
1
tz.transition 1982, 9, :o2, 401850000
-
1
tz.transition 1983, 3, :o3, 417574800
-
1
tz.transition 1983, 9, :o2, 433299600
-
1
tz.transition 1984, 3, :o3, 449024400
-
1
tz.transition 1984, 9, :o2, 465354000
-
1
tz.transition 1985, 3, :o3, 481078800
-
1
tz.transition 1985, 9, :o2, 496803600
-
1
tz.transition 1986, 3, :o3, 512528400
-
1
tz.transition 1986, 9, :o2, 528253200
-
1
tz.transition 1987, 3, :o3, 543978000
-
1
tz.transition 1987, 9, :o2, 559702800
-
1
tz.transition 1988, 3, :o3, 575427600
-
1
tz.transition 1988, 9, :o2, 591152400
-
1
tz.transition 1989, 3, :o3, 606877200
-
1
tz.transition 1989, 9, :o2, 622602000
-
1
tz.transition 1990, 3, :o3, 638326800
-
1
tz.transition 1990, 9, :o2, 654656400
-
1
tz.transition 1991, 3, :o3, 670381200
-
1
tz.transition 1991, 9, :o2, 686106000
-
1
tz.transition 1992, 3, :o3, 701830800
-
1
tz.transition 1992, 9, :o2, 717555600
-
1
tz.transition 1993, 3, :o3, 733280400
-
1
tz.transition 1993, 9, :o2, 749005200
-
1
tz.transition 1994, 3, :o3, 764730000
-
1
tz.transition 1994, 9, :o2, 780454800
-
1
tz.transition 1995, 3, :o3, 796179600
-
1
tz.transition 1995, 9, :o2, 811904400
-
1
tz.transition 1996, 3, :o3, 828234000
-
1
tz.transition 1996, 10, :o2, 846378000
-
1
tz.transition 1997, 3, :o3, 859683600
-
1
tz.transition 1997, 10, :o2, 877827600
-
1
tz.transition 1998, 3, :o3, 891133200
-
1
tz.transition 1998, 10, :o2, 909277200
-
1
tz.transition 1999, 3, :o3, 922582800
-
1
tz.transition 1999, 10, :o2, 941331600
-
1
tz.transition 2000, 3, :o3, 954032400
-
1
tz.transition 2000, 10, :o2, 972781200
-
1
tz.transition 2001, 3, :o3, 985482000
-
1
tz.transition 2001, 10, :o2, 1004230800
-
1
tz.transition 2002, 3, :o3, 1017536400
-
1
tz.transition 2002, 10, :o2, 1035680400
-
1
tz.transition 2003, 3, :o3, 1048986000
-
1
tz.transition 2003, 10, :o2, 1067130000
-
1
tz.transition 2004, 3, :o3, 1080435600
-
1
tz.transition 2004, 10, :o2, 1099184400
-
1
tz.transition 2005, 3, :o3, 1111885200
-
1
tz.transition 2005, 10, :o2, 1130634000
-
1
tz.transition 2006, 3, :o3, 1143334800
-
1
tz.transition 2006, 10, :o2, 1162083600
-
1
tz.transition 2007, 3, :o3, 1174784400
-
1
tz.transition 2007, 10, :o2, 1193533200
-
1
tz.transition 2008, 3, :o3, 1206838800
-
1
tz.transition 2008, 10, :o2, 1224982800
-
1
tz.transition 2009, 3, :o3, 1238288400
-
1
tz.transition 2009, 10, :o2, 1256432400
-
1
tz.transition 2010, 3, :o3, 1269738000
-
1
tz.transition 2010, 10, :o2, 1288486800
-
1
tz.transition 2011, 3, :o3, 1301187600
-
1
tz.transition 2011, 10, :o2, 1319936400
-
1
tz.transition 2012, 3, :o3, 1332637200
-
1
tz.transition 2012, 10, :o2, 1351386000
-
1
tz.transition 2013, 3, :o3, 1364691600
-
1
tz.transition 2013, 10, :o2, 1382835600
-
1
tz.transition 2014, 3, :o3, 1396141200
-
1
tz.transition 2014, 10, :o2, 1414285200
-
1
tz.transition 2015, 3, :o3, 1427590800
-
1
tz.transition 2015, 10, :o2, 1445734800
-
1
tz.transition 2016, 3, :o3, 1459040400
-
1
tz.transition 2016, 10, :o2, 1477789200
-
1
tz.transition 2017, 3, :o3, 1490490000
-
1
tz.transition 2017, 10, :o2, 1509238800
-
1
tz.transition 2018, 3, :o3, 1521939600
-
1
tz.transition 2018, 10, :o2, 1540688400
-
1
tz.transition 2019, 3, :o3, 1553994000
-
1
tz.transition 2019, 10, :o2, 1572138000
-
1
tz.transition 2020, 3, :o3, 1585443600
-
1
tz.transition 2020, 10, :o2, 1603587600
-
1
tz.transition 2021, 3, :o3, 1616893200
-
1
tz.transition 2021, 10, :o2, 1635642000
-
1
tz.transition 2022, 3, :o3, 1648342800
-
1
tz.transition 2022, 10, :o2, 1667091600
-
1
tz.transition 2023, 3, :o3, 1679792400
-
1
tz.transition 2023, 10, :o2, 1698541200
-
1
tz.transition 2024, 3, :o3, 1711846800
-
1
tz.transition 2024, 10, :o2, 1729990800
-
1
tz.transition 2025, 3, :o3, 1743296400
-
1
tz.transition 2025, 10, :o2, 1761440400
-
1
tz.transition 2026, 3, :o3, 1774746000
-
1
tz.transition 2026, 10, :o2, 1792890000
-
1
tz.transition 2027, 3, :o3, 1806195600
-
1
tz.transition 2027, 10, :o2, 1824944400
-
1
tz.transition 2028, 3, :o3, 1837645200
-
1
tz.transition 2028, 10, :o2, 1856394000
-
1
tz.transition 2029, 3, :o3, 1869094800
-
1
tz.transition 2029, 10, :o2, 1887843600
-
1
tz.transition 2030, 3, :o3, 1901149200
-
1
tz.transition 2030, 10, :o2, 1919293200
-
1
tz.transition 2031, 3, :o3, 1932598800
-
1
tz.transition 2031, 10, :o2, 1950742800
-
1
tz.transition 2032, 3, :o3, 1964048400
-
1
tz.transition 2032, 10, :o2, 1982797200
-
1
tz.transition 2033, 3, :o3, 1995498000
-
1
tz.transition 2033, 10, :o2, 2014246800
-
1
tz.transition 2034, 3, :o3, 2026947600
-
1
tz.transition 2034, 10, :o2, 2045696400
-
1
tz.transition 2035, 3, :o3, 2058397200
-
1
tz.transition 2035, 10, :o2, 2077146000
-
1
tz.transition 2036, 3, :o3, 2090451600
-
1
tz.transition 2036, 10, :o2, 2108595600
-
1
tz.transition 2037, 3, :o3, 2121901200
-
1
tz.transition 2037, 10, :o2, 2140045200
-
1
tz.transition 2038, 3, :o3, 59172253, 24
-
1
tz.transition 2038, 10, :o2, 59177461, 24
-
1
tz.transition 2039, 3, :o3, 59180989, 24
-
1
tz.transition 2039, 10, :o2, 59186197, 24
-
1
tz.transition 2040, 3, :o3, 59189725, 24
-
1
tz.transition 2040, 10, :o2, 59194933, 24
-
1
tz.transition 2041, 3, :o3, 59198629, 24
-
1
tz.transition 2041, 10, :o2, 59203669, 24
-
1
tz.transition 2042, 3, :o3, 59207365, 24
-
1
tz.transition 2042, 10, :o2, 59212405, 24
-
1
tz.transition 2043, 3, :o3, 59216101, 24
-
1
tz.transition 2043, 10, :o2, 59221141, 24
-
1
tz.transition 2044, 3, :o3, 59224837, 24
-
1
tz.transition 2044, 10, :o2, 59230045, 24
-
1
tz.transition 2045, 3, :o3, 59233573, 24
-
1
tz.transition 2045, 10, :o2, 59238781, 24
-
1
tz.transition 2046, 3, :o3, 59242309, 24
-
1
tz.transition 2046, 10, :o2, 59247517, 24
-
1
tz.transition 2047, 3, :o3, 59251213, 24
-
1
tz.transition 2047, 10, :o2, 59256253, 24
-
1
tz.transition 2048, 3, :o3, 59259949, 24
-
1
tz.transition 2048, 10, :o2, 59264989, 24
-
1
tz.transition 2049, 3, :o3, 59268685, 24
-
1
tz.transition 2049, 10, :o2, 59273893, 24
-
1
tz.transition 2050, 3, :o3, 59277421, 24
-
1
tz.transition 2050, 10, :o2, 59282629, 24
-
end
-
end
-
end
-
end
-
end
-
1
module TZInfo
-
1
module Definitions
-
1
module Europe
-
1
module Riga
-
1
include TimezoneDefinition
-
-
1
timezone 'Europe/Riga' do |tz|
-
1
tz.offset :o0, 5784, 0, :LMT
-
1
tz.offset :o1, 5784, 0, :RMT
-
1
tz.offset :o2, 5784, 3600, :LST
-
1
tz.offset :o3, 7200, 0, :EET
-
1
tz.offset :o4, 10800, 0, :MSK
-
1
tz.offset :o5, 3600, 3600, :CEST
-
1
tz.offset :o6, 3600, 0, :CET
-
1
tz.offset :o7, 10800, 3600, :MSD
-
1
tz.offset :o8, 7200, 3600, :EEST
-
-
1
tz.transition 1879, 12, :o1, 8667775559, 3600
-
1
tz.transition 1918, 4, :o2, 8718114659, 3600
-
1
tz.transition 1918, 9, :o1, 8718669059, 3600
-
1
tz.transition 1919, 4, :o2, 8719378259, 3600
-
1
tz.transition 1919, 5, :o1, 8719561859, 3600
-
1
tz.transition 1926, 5, :o3, 8728727159, 3600
-
1
tz.transition 1940, 8, :o4, 29158157, 12
-
1
tz.transition 1941, 6, :o5, 19441411, 8
-
1
tz.transition 1942, 11, :o6, 58335973, 24
-
1
tz.transition 1943, 3, :o5, 58339501, 24
-
1
tz.transition 1943, 10, :o6, 58344037, 24
-
1
tz.transition 1944, 4, :o5, 58348405, 24
-
1
tz.transition 1944, 10, :o6, 58352773, 24
-
1
tz.transition 1944, 10, :o4, 58353035, 24
-
1
tz.transition 1981, 3, :o7, 354920400
-
1
tz.transition 1981, 9, :o4, 370728000
-
1
tz.transition 1982, 3, :o7, 386456400
-
1
tz.transition 1982, 9, :o4, 402264000
-
1
tz.transition 1983, 3, :o7, 417992400
-
1
tz.transition 1983, 9, :o4, 433800000
-
1
tz.transition 1984, 3, :o7, 449614800
-
1
tz.transition 1984, 9, :o4, 465346800
-
1
tz.transition 1985, 3, :o7, 481071600
-
1
tz.transition 1985, 9, :o4, 496796400
-
1
tz.transition 1986, 3, :o7, 512521200
-
1
tz.transition 1986, 9, :o4, 528246000
-
1
tz.transition 1987, 3, :o7, 543970800
-
1
tz.transition 1987, 9, :o4, 559695600
-
1
tz.transition 1988, 3, :o7, 575420400
-
1
tz.transition 1988, 9, :o4, 591145200
-
1
tz.transition 1989, 3, :o8, 606870000
-
1
tz.transition 1989, 9, :o3, 622598400
-
1
tz.transition 1990, 3, :o8, 638323200
-
1
tz.transition 1990, 9, :o3, 654652800
-
1
tz.transition 1991, 3, :o8, 670377600
-
1
tz.transition 1991, 9, :o3, 686102400
-
1
tz.transition 1992, 3, :o8, 701827200
-
1
tz.transition 1992, 9, :o3, 717552000
-
1
tz.transition 1993, 3, :o8, 733276800
-
1
tz.transition 1993, 9, :o3, 749001600
-
1
tz.transition 1994, 3, :o8, 764726400
-
1
tz.transition 1994, 9, :o3, 780451200
-
1
tz.transition 1995, 3, :o8, 796176000
-
1
tz.transition 1995, 9, :o3, 811900800
-
1
tz.transition 1996, 3, :o8, 828230400
-
1
tz.transition 1996, 9, :o3, 843955200
-
1
tz.transition 1997, 3, :o8, 859683600
-
1
tz.transition 1997, 10, :o3, 877827600
-
1
tz.transition 1998, 3, :o8, 891133200
-
1
tz.transition 1998, 10, :o3, 909277200
-
1
tz.transition 1999, 3, :o8, 922582800
-
1
tz.transition 1999, 10, :o3, 941331600
-
1
tz.transition 2001, 3, :o8, 985482000
-
1
tz.transition 2001, 10, :o3, 1004230800
-
1
tz.transition 2002, 3, :o8, 1017536400
-
1
tz.transition 2002, 10, :o3, 1035680400
-
1
tz.transition 2003, 3, :o8, 1048986000
-
1
tz.transition 2003, 10, :o3, 1067130000
-
1
tz.transition 2004, 3, :o8, 1080435600
-
1
tz.transition 2004, 10, :o3, 1099184400
-
1
tz.transition 2005, 3, :o8, 1111885200
-
1
tz.transition 2005, 10, :o3, 1130634000
-
1
tz.transition 2006, 3, :o8, 1143334800
-
1
tz.transition 2006, 10, :o3, 1162083600
-
1
tz.transition 2007, 3, :o8, 1174784400
-
1
tz.transition 2007, 10, :o3, 1193533200
-
1
tz.transition 2008, 3, :o8, 1206838800
-
1
tz.transition 2008, 10, :o3, 1224982800
-
1
tz.transition 2009, 3, :o8, 1238288400
-
1
tz.transition 2009, 10, :o3, 1256432400
-
1
tz.transition 2010, 3, :o8, 1269738000
-
1
tz.transition 2010, 10, :o3, 1288486800
-
1
tz.transition 2011, 3, :o8, 1301187600
-
1
tz.transition 2011, 10, :o3, 1319936400
-
1
tz.transition 2012, 3, :o8, 1332637200
-
1
tz.transition 2012, 10, :o3, 1351386000
-
1
tz.transition 2013, 3, :o8, 1364691600
-
1
tz.transition 2013, 10, :o3, 1382835600
-
1
tz.transition 2014, 3, :o8, 1396141200
-
1
tz.transition 2014, 10, :o3, 1414285200
-
1
tz.transition 2015, 3, :o8, 1427590800
-
1
tz.transition 2015, 10, :o3, 1445734800
-
1
tz.transition 2016, 3, :o8, 1459040400
-
1
tz.transition 2016, 10, :o3, 1477789200
-
1
tz.transition 2017, 3, :o8, 1490490000
-
1
tz.transition 2017, 10, :o3, 1509238800
-
1
tz.transition 2018, 3, :o8, 1521939600
-
1
tz.transition 2018, 10, :o3, 1540688400
-
1
tz.transition 2019, 3, :o8, 1553994000
-
1
tz.transition 2019, 10, :o3, 1572138000
-
1
tz.transition 2020, 3, :o8, 1585443600
-
1
tz.transition 2020, 10, :o3, 1603587600
-
1
tz.transition 2021, 3, :o8, 1616893200
-
1
tz.transition 2021, 10, :o3, 1635642000
-
1
tz.transition 2022, 3, :o8, 1648342800
-
1
tz.transition 2022, 10, :o3, 1667091600
-
1
tz.transition 2023, 3, :o8, 1679792400
-
1
tz.transition 2023, 10, :o3, 1698541200
-
1
tz.transition 2024, 3, :o8, 1711846800
-
1
tz.transition 2024, 10, :o3, 1729990800
-
1
tz.transition 2025, 3, :o8, 1743296400
-
1
tz.transition 2025, 10, :o3, 1761440400
-
1
tz.transition 2026, 3, :o8, 1774746000
-
1
tz.transition 2026, 10, :o3, 1792890000
-
1
tz.transition 2027, 3, :o8, 1806195600
-
1
tz.transition 2027, 10, :o3, 1824944400
-
1
tz.transition 2028, 3, :o8, 1837645200
-
1
tz.transition 2028, 10, :o3, 1856394000
-
1
tz.transition 2029, 3, :o8, 1869094800
-
1
tz.transition 2029, 10, :o3, 1887843600
-
1
tz.transition 2030, 3, :o8, 1901149200
-
1
tz.transition 2030, 10, :o3, 1919293200
-
1
tz.transition 2031, 3, :o8, 1932598800
-
1
tz.transition 2031, 10, :o3, 1950742800
-
1
tz.transition 2032, 3, :o8, 1964048400
-
1
tz.transition 2032, 10, :o3, 1982797200
-
1
tz.transition 2033, 3, :o8, 1995498000
-
1
tz.transition 2033, 10, :o3, 2014246800
-
1
tz.transition 2034, 3, :o8, 2026947600
-
1
tz.transition 2034, 10, :o3, 2045696400
-
1
tz.transition 2035, 3, :o8, 2058397200
-
1
tz.transition 2035, 10, :o3, 2077146000
-
1
tz.transition 2036, 3, :o8, 2090451600
-
1
tz.transition 2036, 10, :o3, 2108595600
-
1
tz.transition 2037, 3, :o8, 2121901200
-
1
tz.transition 2037, 10, :o3, 2140045200
-
1
tz.transition 2038, 3, :o8, 59172253, 24
-
1
tz.transition 2038, 10, :o3, 59177461, 24
-
1
tz.transition 2039, 3, :o8, 59180989, 24
-
1
tz.transition 2039, 10, :o3, 59186197, 24
-
1
tz.transition 2040, 3, :o8, 59189725, 24
-
1
tz.transition 2040, 10, :o3, 59194933, 24
-
1
tz.transition 2041, 3, :o8, 59198629, 24
-
1
tz.transition 2041, 10, :o3, 59203669, 24
-
1
tz.transition 2042, 3, :o8, 59207365, 24
-
1
tz.transition 2042, 10, :o3, 59212405, 24
-
1
tz.transition 2043, 3, :o8, 59216101, 24
-
1
tz.transition 2043, 10, :o3, 59221141, 24
-
1
tz.transition 2044, 3, :o8, 59224837, 24
-
1
tz.transition 2044, 10, :o3, 59230045, 24
-
1
tz.transition 2045, 3, :o8, 59233573, 24
-
1
tz.transition 2045, 10, :o3, 59238781, 24
-
1
tz.transition 2046, 3, :o8, 59242309, 24
-
1
tz.transition 2046, 10, :o3, 59247517, 24
-
1
tz.transition 2047, 3, :o8, 59251213, 24
-
1
tz.transition 2047, 10, :o3, 59256253, 24
-
1
tz.transition 2048, 3, :o8, 59259949, 24
-
1
tz.transition 2048, 10, :o3, 59264989, 24
-
1
tz.transition 2049, 3, :o8, 59268685, 24
-
1
tz.transition 2049, 10, :o3, 59273893, 24
-
1
tz.transition 2050, 3, :o8, 59277421, 24
-
1
tz.transition 2050, 10, :o3, 59282629, 24
-
end
-
end
-
end
-
end
-
end
-
1
module TZInfo
-
1
module Definitions
-
1
module Europe
-
1
module Rome
-
1
include TimezoneDefinition
-
-
1
timezone 'Europe/Rome' do |tz|
-
1
tz.offset :o0, 2996, 0, :LMT
-
1
tz.offset :o1, 2996, 0, :RMT
-
1
tz.offset :o2, 3600, 0, :CET
-
1
tz.offset :o3, 3600, 3600, :CEST
-
-
1
tz.transition 1866, 9, :o1, 51901915651, 21600
-
1
tz.transition 1893, 10, :o2, 52115798851, 21600
-
1
tz.transition 1916, 6, :o3, 58104419, 24
-
1
tz.transition 1916, 9, :o2, 58107299, 24
-
1
tz.transition 1917, 3, :o3, 58111667, 24
-
1
tz.transition 1917, 9, :o2, 58116035, 24
-
1
tz.transition 1918, 3, :o3, 58119899, 24
-
1
tz.transition 1918, 10, :o2, 58124939, 24
-
1
tz.transition 1919, 3, :o3, 58128467, 24
-
1
tz.transition 1919, 10, :o2, 58133675, 24
-
1
tz.transition 1920, 3, :o3, 58137707, 24
-
1
tz.transition 1920, 9, :o2, 58142075, 24
-
1
tz.transition 1940, 6, :o3, 58315091, 24
-
1
tz.transition 1942, 11, :o2, 58335973, 24
-
1
tz.transition 1943, 3, :o3, 58339501, 24
-
1
tz.transition 1943, 10, :o2, 58344037, 24
-
1
tz.transition 1944, 4, :o3, 58348405, 24
-
1
tz.transition 1944, 9, :o2, 58352411, 24
-
1
tz.transition 1945, 4, :o3, 58357141, 24
-
1
tz.transition 1945, 9, :o2, 58361123, 24
-
1
tz.transition 1946, 3, :o3, 58365517, 24
-
1
tz.transition 1946, 10, :o2, 58370389, 24
-
1
tz.transition 1947, 3, :o3, 58374251, 24
-
1
tz.transition 1947, 10, :o2, 58379123, 24
-
1
tz.transition 1948, 2, :o3, 58382653, 24
-
1
tz.transition 1948, 10, :o2, 58387861, 24
-
1
tz.transition 1966, 5, :o3, 58542419, 24
-
1
tz.transition 1966, 9, :o2, 29272721, 12
-
1
tz.transition 1967, 5, :o3, 58551323, 24
-
1
tz.transition 1967, 9, :o2, 29277089, 12
-
1
tz.transition 1968, 5, :o3, 58560059, 24
-
1
tz.transition 1968, 9, :o2, 29281457, 12
-
1
tz.transition 1969, 5, :o3, 58568963, 24
-
1
tz.transition 1969, 9, :o2, 29285909, 12
-
1
tz.transition 1970, 5, :o3, 12956400
-
1
tz.transition 1970, 9, :o2, 23234400
-
1
tz.transition 1971, 5, :o3, 43801200
-
1
tz.transition 1971, 9, :o2, 54687600
-
1
tz.transition 1972, 5, :o3, 75855600
-
1
tz.transition 1972, 9, :o2, 86738400
-
1
tz.transition 1973, 6, :o3, 107910000
-
1
tz.transition 1973, 9, :o2, 118188000
-
1
tz.transition 1974, 5, :o3, 138754800
-
1
tz.transition 1974, 9, :o2, 149637600
-
1
tz.transition 1975, 5, :o3, 170809200
-
1
tz.transition 1975, 9, :o2, 181090800
-
1
tz.transition 1976, 5, :o3, 202258800
-
1
tz.transition 1976, 9, :o2, 212540400
-
1
tz.transition 1977, 5, :o3, 233103600
-
1
tz.transition 1977, 9, :o2, 243990000
-
1
tz.transition 1978, 5, :o3, 265158000
-
1
tz.transition 1978, 9, :o2, 276044400
-
1
tz.transition 1979, 5, :o3, 296607600
-
1
tz.transition 1979, 9, :o2, 307494000
-
1
tz.transition 1980, 4, :o3, 323830800
-
1
tz.transition 1980, 9, :o2, 338950800
-
1
tz.transition 1981, 3, :o3, 354675600
-
1
tz.transition 1981, 9, :o2, 370400400
-
1
tz.transition 1982, 3, :o3, 386125200
-
1
tz.transition 1982, 9, :o2, 401850000
-
1
tz.transition 1983, 3, :o3, 417574800
-
1
tz.transition 1983, 9, :o2, 433299600
-
1
tz.transition 1984, 3, :o3, 449024400
-
1
tz.transition 1984, 9, :o2, 465354000
-
1
tz.transition 1985, 3, :o3, 481078800
-
1
tz.transition 1985, 9, :o2, 496803600
-
1
tz.transition 1986, 3, :o3, 512528400
-
1
tz.transition 1986, 9, :o2, 528253200
-
1
tz.transition 1987, 3, :o3, 543978000
-
1
tz.transition 1987, 9, :o2, 559702800
-
1
tz.transition 1988, 3, :o3, 575427600
-
1
tz.transition 1988, 9, :o2, 591152400
-
1
tz.transition 1989, 3, :o3, 606877200
-
1
tz.transition 1989, 9, :o2, 622602000
-
1
tz.transition 1990, 3, :o3, 638326800
-
1
tz.transition 1990, 9, :o2, 654656400
-
1
tz.transition 1991, 3, :o3, 670381200
-
1
tz.transition 1991, 9, :o2, 686106000
-
1
tz.transition 1992, 3, :o3, 701830800
-
1
tz.transition 1992, 9, :o2, 717555600
-
1
tz.transition 1993, 3, :o3, 733280400
-
1
tz.transition 1993, 9, :o2, 749005200
-
1
tz.transition 1994, 3, :o3, 764730000
-
1
tz.transition 1994, 9, :o2, 780454800
-
1
tz.transition 1995, 3, :o3, 796179600
-
1
tz.transition 1995, 9, :o2, 811904400
-
1
tz.transition 1996, 3, :o3, 828234000
-
1
tz.transition 1996, 10, :o2, 846378000
-
1
tz.transition 1997, 3, :o3, 859683600
-
1
tz.transition 1997, 10, :o2, 877827600
-
1
tz.transition 1998, 3, :o3, 891133200
-
1
tz.transition 1998, 10, :o2, 909277200
-
1
tz.transition 1999, 3, :o3, 922582800
-
1
tz.transition 1999, 10, :o2, 941331600
-
1
tz.transition 2000, 3, :o3, 954032400
-
1
tz.transition 2000, 10, :o2, 972781200
-
1
tz.transition 2001, 3, :o3, 985482000
-
1
tz.transition 2001, 10, :o2, 1004230800
-
1
tz.transition 2002, 3, :o3, 1017536400
-
1
tz.transition 2002, 10, :o2, 1035680400
-
1
tz.transition 2003, 3, :o3, 1048986000
-
1
tz.transition 2003, 10, :o2, 1067130000
-
1
tz.transition 2004, 3, :o3, 1080435600
-
1
tz.transition 2004, 10, :o2, 1099184400
-
1
tz.transition 2005, 3, :o3, 1111885200
-
1
tz.transition 2005, 10, :o2, 1130634000
-
1
tz.transition 2006, 3, :o3, 1143334800
-
1
tz.transition 2006, 10, :o2, 1162083600
-
1
tz.transition 2007, 3, :o3, 1174784400
-
1
tz.transition 2007, 10, :o2, 1193533200
-
1
tz.transition 2008, 3, :o3, 1206838800
-
1
tz.transition 2008, 10, :o2, 1224982800
-
1
tz.transition 2009, 3, :o3, 1238288400
-
1
tz.transition 2009, 10, :o2, 1256432400
-
1
tz.transition 2010, 3, :o3, 1269738000
-
1
tz.transition 2010, 10, :o2, 1288486800
-
1
tz.transition 2011, 3, :o3, 1301187600
-
1
tz.transition 2011, 10, :o2, 1319936400
-
1
tz.transition 2012, 3, :o3, 1332637200
-
1
tz.transition 2012, 10, :o2, 1351386000
-
1
tz.transition 2013, 3, :o3, 1364691600
-
1
tz.transition 2013, 10, :o2, 1382835600
-
1
tz.transition 2014, 3, :o3, 1396141200
-
1
tz.transition 2014, 10, :o2, 1414285200
-
1
tz.transition 2015, 3, :o3, 1427590800
-
1
tz.transition 2015, 10, :o2, 1445734800
-
1
tz.transition 2016, 3, :o3, 1459040400
-
1
tz.transition 2016, 10, :o2, 1477789200
-
1
tz.transition 2017, 3, :o3, 1490490000
-
1
tz.transition 2017, 10, :o2, 1509238800
-
1
tz.transition 2018, 3, :o3, 1521939600
-
1
tz.transition 2018, 10, :o2, 1540688400
-
1
tz.transition 2019, 3, :o3, 1553994000
-
1
tz.transition 2019, 10, :o2, 1572138000
-
1
tz.transition 2020, 3, :o3, 1585443600
-
1
tz.transition 2020, 10, :o2, 1603587600
-
1
tz.transition 2021, 3, :o3, 1616893200
-
1
tz.transition 2021, 10, :o2, 1635642000
-
1
tz.transition 2022, 3, :o3, 1648342800
-
1
tz.transition 2022, 10, :o2, 1667091600
-
1
tz.transition 2023, 3, :o3, 1679792400
-
1
tz.transition 2023, 10, :o2, 1698541200
-
1
tz.transition 2024, 3, :o3, 1711846800
-
1
tz.transition 2024, 10, :o2, 1729990800
-
1
tz.transition 2025, 3, :o3, 1743296400
-
1
tz.transition 2025, 10, :o2, 1761440400
-
1
tz.transition 2026, 3, :o3, 1774746000
-
1
tz.transition 2026, 10, :o2, 1792890000
-
1
tz.transition 2027, 3, :o3, 1806195600
-
1
tz.transition 2027, 10, :o2, 1824944400
-
1
tz.transition 2028, 3, :o3, 1837645200
-
1
tz.transition 2028, 10, :o2, 1856394000
-
1
tz.transition 2029, 3, :o3, 1869094800
-
1
tz.transition 2029, 10, :o2, 1887843600
-
1
tz.transition 2030, 3, :o3, 1901149200
-
1
tz.transition 2030, 10, :o2, 1919293200
-
1
tz.transition 2031, 3, :o3, 1932598800
-
1
tz.transition 2031, 10, :o2, 1950742800
-
1
tz.transition 2032, 3, :o3, 1964048400
-
1
tz.transition 2032, 10, :o2, 1982797200
-
1
tz.transition 2033, 3, :o3, 1995498000
-
1
tz.transition 2033, 10, :o2, 2014246800
-
1
tz.transition 2034, 3, :o3, 2026947600
-
1
tz.transition 2034, 10, :o2, 2045696400
-
1
tz.transition 2035, 3, :o3, 2058397200
-
1
tz.transition 2035, 10, :o2, 2077146000
-
1
tz.transition 2036, 3, :o3, 2090451600
-
1
tz.transition 2036, 10, :o2, 2108595600
-
1
tz.transition 2037, 3, :o3, 2121901200
-
1
tz.transition 2037, 10, :o2, 2140045200
-
1
tz.transition 2038, 3, :o3, 59172253, 24
-
1
tz.transition 2038, 10, :o2, 59177461, 24
-
1
tz.transition 2039, 3, :o3, 59180989, 24
-
1
tz.transition 2039, 10, :o2, 59186197, 24
-
1
tz.transition 2040, 3, :o3, 59189725, 24
-
1
tz.transition 2040, 10, :o2, 59194933, 24
-
1
tz.transition 2041, 3, :o3, 59198629, 24
-
1
tz.transition 2041, 10, :o2, 59203669, 24
-
1
tz.transition 2042, 3, :o3, 59207365, 24
-
1
tz.transition 2042, 10, :o2, 59212405, 24
-
1
tz.transition 2043, 3, :o3, 59216101, 24
-
1
tz.transition 2043, 10, :o2, 59221141, 24
-
1
tz.transition 2044, 3, :o3, 59224837, 24
-
1
tz.transition 2044, 10, :o2, 59230045, 24
-
1
tz.transition 2045, 3, :o3, 59233573, 24
-
1
tz.transition 2045, 10, :o2, 59238781, 24
-
1
tz.transition 2046, 3, :o3, 59242309, 24
-
1
tz.transition 2046, 10, :o2, 59247517, 24
-
1
tz.transition 2047, 3, :o3, 59251213, 24
-
1
tz.transition 2047, 10, :o2, 59256253, 24
-
1
tz.transition 2048, 3, :o3, 59259949, 24
-
1
tz.transition 2048, 10, :o2, 59264989, 24
-
1
tz.transition 2049, 3, :o3, 59268685, 24
-
1
tz.transition 2049, 10, :o2, 59273893, 24
-
1
tz.transition 2050, 3, :o3, 59277421, 24
-
1
tz.transition 2050, 10, :o2, 59282629, 24
-
end
-
end
-
end
-
end
-
end
-
1
module TZInfo
-
1
module Definitions
-
1
module Europe
-
1
module Sarajevo
-
1
include TimezoneDefinition
-
-
1
linked_timezone 'Europe/Sarajevo', 'Europe/Belgrade'
-
end
-
end
-
end
-
end
-
1
module TZInfo
-
1
module Definitions
-
1
module Europe
-
1
module Skopje
-
1
include TimezoneDefinition
-
-
1
linked_timezone 'Europe/Skopje', 'Europe/Belgrade'
-
end
-
end
-
end
-
end
-
1
module TZInfo
-
1
module Definitions
-
1
module Europe
-
1
module Sofia
-
1
include TimezoneDefinition
-
-
1
timezone 'Europe/Sofia' do |tz|
-
1
tz.offset :o0, 5596, 0, :LMT
-
1
tz.offset :o1, 7016, 0, :IMT
-
1
tz.offset :o2, 7200, 0, :EET
-
1
tz.offset :o3, 3600, 0, :CET
-
1
tz.offset :o4, 3600, 3600, :CEST
-
1
tz.offset :o5, 7200, 3600, :EEST
-
-
1
tz.transition 1879, 12, :o1, 52006653401, 21600
-
1
tz.transition 1894, 11, :o2, 26062154123, 10800
-
1
tz.transition 1942, 11, :o3, 58335973, 24
-
1
tz.transition 1943, 3, :o4, 58339501, 24
-
1
tz.transition 1943, 10, :o3, 58344037, 24
-
1
tz.transition 1944, 4, :o4, 58348405, 24
-
1
tz.transition 1944, 10, :o3, 58352773, 24
-
1
tz.transition 1945, 4, :o2, 29178571, 12
-
1
tz.transition 1979, 3, :o5, 291762000
-
1
tz.transition 1979, 9, :o2, 307576800
-
1
tz.transition 1980, 4, :o5, 323816400
-
1
tz.transition 1980, 9, :o2, 339026400
-
1
tz.transition 1981, 4, :o5, 355266000
-
1
tz.transition 1981, 9, :o2, 370393200
-
1
tz.transition 1982, 4, :o5, 386715600
-
1
tz.transition 1982, 9, :o2, 401846400
-
1
tz.transition 1983, 3, :o5, 417571200
-
1
tz.transition 1983, 9, :o2, 433296000
-
1
tz.transition 1984, 3, :o5, 449020800
-
1
tz.transition 1984, 9, :o2, 465350400
-
1
tz.transition 1985, 3, :o5, 481075200
-
1
tz.transition 1985, 9, :o2, 496800000
-
1
tz.transition 1986, 3, :o5, 512524800
-
1
tz.transition 1986, 9, :o2, 528249600
-
1
tz.transition 1987, 3, :o5, 543974400
-
1
tz.transition 1987, 9, :o2, 559699200
-
1
tz.transition 1988, 3, :o5, 575424000
-
1
tz.transition 1988, 9, :o2, 591148800
-
1
tz.transition 1989, 3, :o5, 606873600
-
1
tz.transition 1989, 9, :o2, 622598400
-
1
tz.transition 1990, 3, :o5, 638323200
-
1
tz.transition 1990, 9, :o2, 654652800
-
1
tz.transition 1991, 3, :o5, 670370400
-
1
tz.transition 1991, 9, :o2, 686091600
-
1
tz.transition 1992, 3, :o5, 701820000
-
1
tz.transition 1992, 9, :o2, 717541200
-
1
tz.transition 1993, 3, :o5, 733269600
-
1
tz.transition 1993, 9, :o2, 748990800
-
1
tz.transition 1994, 3, :o5, 764719200
-
1
tz.transition 1994, 9, :o2, 780440400
-
1
tz.transition 1995, 3, :o5, 796168800
-
1
tz.transition 1995, 9, :o2, 811890000
-
1
tz.transition 1996, 3, :o5, 828223200
-
1
tz.transition 1996, 10, :o2, 846363600
-
1
tz.transition 1997, 3, :o5, 859683600
-
1
tz.transition 1997, 10, :o2, 877827600
-
1
tz.transition 1998, 3, :o5, 891133200
-
1
tz.transition 1998, 10, :o2, 909277200
-
1
tz.transition 1999, 3, :o5, 922582800
-
1
tz.transition 1999, 10, :o2, 941331600
-
1
tz.transition 2000, 3, :o5, 954032400
-
1
tz.transition 2000, 10, :o2, 972781200
-
1
tz.transition 2001, 3, :o5, 985482000
-
1
tz.transition 2001, 10, :o2, 1004230800
-
1
tz.transition 2002, 3, :o5, 1017536400
-
1
tz.transition 2002, 10, :o2, 1035680400
-
1
tz.transition 2003, 3, :o5, 1048986000
-
1
tz.transition 2003, 10, :o2, 1067130000
-
1
tz.transition 2004, 3, :o5, 1080435600
-
1
tz.transition 2004, 10, :o2, 1099184400
-
1
tz.transition 2005, 3, :o5, 1111885200
-
1
tz.transition 2005, 10, :o2, 1130634000
-
1
tz.transition 2006, 3, :o5, 1143334800
-
1
tz.transition 2006, 10, :o2, 1162083600
-
1
tz.transition 2007, 3, :o5, 1174784400
-
1
tz.transition 2007, 10, :o2, 1193533200
-
1
tz.transition 2008, 3, :o5, 1206838800
-
1
tz.transition 2008, 10, :o2, 1224982800
-
1
tz.transition 2009, 3, :o5, 1238288400
-
1
tz.transition 2009, 10, :o2, 1256432400
-
1
tz.transition 2010, 3, :o5, 1269738000
-
1
tz.transition 2010, 10, :o2, 1288486800
-
1
tz.transition 2011, 3, :o5, 1301187600
-
1
tz.transition 2011, 10, :o2, 1319936400
-
1
tz.transition 2012, 3, :o5, 1332637200
-
1
tz.transition 2012, 10, :o2, 1351386000
-
1
tz.transition 2013, 3, :o5, 1364691600
-
1
tz.transition 2013, 10, :o2, 1382835600
-
1
tz.transition 2014, 3, :o5, 1396141200
-
1
tz.transition 2014, 10, :o2, 1414285200
-
1
tz.transition 2015, 3, :o5, 1427590800
-
1
tz.transition 2015, 10, :o2, 1445734800
-
1
tz.transition 2016, 3, :o5, 1459040400
-
1
tz.transition 2016, 10, :o2, 1477789200
-
1
tz.transition 2017, 3, :o5, 1490490000
-
1
tz.transition 2017, 10, :o2, 1509238800
-
1
tz.transition 2018, 3, :o5, 1521939600
-
1
tz.transition 2018, 10, :o2, 1540688400
-
1
tz.transition 2019, 3, :o5, 1553994000
-
1
tz.transition 2019, 10, :o2, 1572138000
-
1
tz.transition 2020, 3, :o5, 1585443600
-
1
tz.transition 2020, 10, :o2, 1603587600
-
1
tz.transition 2021, 3, :o5, 1616893200
-
1
tz.transition 2021, 10, :o2, 1635642000
-
1
tz.transition 2022, 3, :o5, 1648342800
-
1
tz.transition 2022, 10, :o2, 1667091600
-
1
tz.transition 2023, 3, :o5, 1679792400
-
1
tz.transition 2023, 10, :o2, 1698541200
-
1
tz.transition 2024, 3, :o5, 1711846800
-
1
tz.transition 2024, 10, :o2, 1729990800
-
1
tz.transition 2025, 3, :o5, 1743296400
-
1
tz.transition 2025, 10, :o2, 1761440400
-
1
tz.transition 2026, 3, :o5, 1774746000
-
1
tz.transition 2026, 10, :o2, 1792890000
-
1
tz.transition 2027, 3, :o5, 1806195600
-
1
tz.transition 2027, 10, :o2, 1824944400
-
1
tz.transition 2028, 3, :o5, 1837645200
-
1
tz.transition 2028, 10, :o2, 1856394000
-
1
tz.transition 2029, 3, :o5, 1869094800
-
1
tz.transition 2029, 10, :o2, 1887843600
-
1
tz.transition 2030, 3, :o5, 1901149200
-
1
tz.transition 2030, 10, :o2, 1919293200
-
1
tz.transition 2031, 3, :o5, 1932598800
-
1
tz.transition 2031, 10, :o2, 1950742800
-
1
tz.transition 2032, 3, :o5, 1964048400
-
1
tz.transition 2032, 10, :o2, 1982797200
-
1
tz.transition 2033, 3, :o5, 1995498000
-
1
tz.transition 2033, 10, :o2, 2014246800
-
1
tz.transition 2034, 3, :o5, 2026947600
-
1
tz.transition 2034, 10, :o2, 2045696400
-
1
tz.transition 2035, 3, :o5, 2058397200
-
1
tz.transition 2035, 10, :o2, 2077146000
-
1
tz.transition 2036, 3, :o5, 2090451600
-
1
tz.transition 2036, 10, :o2, 2108595600
-
1
tz.transition 2037, 3, :o5, 2121901200
-
1
tz.transition 2037, 10, :o2, 2140045200
-
1
tz.transition 2038, 3, :o5, 59172253, 24
-
1
tz.transition 2038, 10, :o2, 59177461, 24
-
1
tz.transition 2039, 3, :o5, 59180989, 24
-
1
tz.transition 2039, 10, :o2, 59186197, 24
-
1
tz.transition 2040, 3, :o5, 59189725, 24
-
1
tz.transition 2040, 10, :o2, 59194933, 24
-
1
tz.transition 2041, 3, :o5, 59198629, 24
-
1
tz.transition 2041, 10, :o2, 59203669, 24
-
1
tz.transition 2042, 3, :o5, 59207365, 24
-
1
tz.transition 2042, 10, :o2, 59212405, 24
-
1
tz.transition 2043, 3, :o5, 59216101, 24
-
1
tz.transition 2043, 10, :o2, 59221141, 24
-
1
tz.transition 2044, 3, :o5, 59224837, 24
-
1
tz.transition 2044, 10, :o2, 59230045, 24
-
1
tz.transition 2045, 3, :o5, 59233573, 24
-
1
tz.transition 2045, 10, :o2, 59238781, 24
-
1
tz.transition 2046, 3, :o5, 59242309, 24
-
1
tz.transition 2046, 10, :o2, 59247517, 24
-
1
tz.transition 2047, 3, :o5, 59251213, 24
-
1
tz.transition 2047, 10, :o2, 59256253, 24
-
1
tz.transition 2048, 3, :o5, 59259949, 24
-
1
tz.transition 2048, 10, :o2, 59264989, 24
-
1
tz.transition 2049, 3, :o5, 59268685, 24
-
1
tz.transition 2049, 10, :o2, 59273893, 24
-
1
tz.transition 2050, 3, :o5, 59277421, 24
-
1
tz.transition 2050, 10, :o2, 59282629, 24
-
end
-
end
-
end
-
end
-
end
-
1
module TZInfo
-
1
module Definitions
-
1
module Europe
-
1
module Stockholm
-
1
include TimezoneDefinition
-
-
1
timezone 'Europe/Stockholm' do |tz|
-
1
tz.offset :o0, 4332, 0, :LMT
-
1
tz.offset :o1, 3614, 0, :SET
-
1
tz.offset :o2, 3600, 0, :CET
-
1
tz.offset :o3, 3600, 3600, :CEST
-
-
1
tz.transition 1878, 12, :o1, 17332923239, 7200
-
1
tz.transition 1899, 12, :o2, 104328883793, 43200
-
1
tz.transition 1916, 5, :o3, 29051981, 12
-
1
tz.transition 1916, 9, :o2, 58107299, 24
-
1
tz.transition 1980, 4, :o3, 323830800
-
1
tz.transition 1980, 9, :o2, 338950800
-
1
tz.transition 1981, 3, :o3, 354675600
-
1
tz.transition 1981, 9, :o2, 370400400
-
1
tz.transition 1982, 3, :o3, 386125200
-
1
tz.transition 1982, 9, :o2, 401850000
-
1
tz.transition 1983, 3, :o3, 417574800
-
1
tz.transition 1983, 9, :o2, 433299600
-
1
tz.transition 1984, 3, :o3, 449024400
-
1
tz.transition 1984, 9, :o2, 465354000
-
1
tz.transition 1985, 3, :o3, 481078800
-
1
tz.transition 1985, 9, :o2, 496803600
-
1
tz.transition 1986, 3, :o3, 512528400
-
1
tz.transition 1986, 9, :o2, 528253200
-
1
tz.transition 1987, 3, :o3, 543978000
-
1
tz.transition 1987, 9, :o2, 559702800
-
1
tz.transition 1988, 3, :o3, 575427600
-
1
tz.transition 1988, 9, :o2, 591152400
-
1
tz.transition 1989, 3, :o3, 606877200
-
1
tz.transition 1989, 9, :o2, 622602000
-
1
tz.transition 1990, 3, :o3, 638326800
-
1
tz.transition 1990, 9, :o2, 654656400
-
1
tz.transition 1991, 3, :o3, 670381200
-
1
tz.transition 1991, 9, :o2, 686106000
-
1
tz.transition 1992, 3, :o3, 701830800
-
1
tz.transition 1992, 9, :o2, 717555600
-
1
tz.transition 1993, 3, :o3, 733280400
-
1
tz.transition 1993, 9, :o2, 749005200
-
1
tz.transition 1994, 3, :o3, 764730000
-
1
tz.transition 1994, 9, :o2, 780454800
-
1
tz.transition 1995, 3, :o3, 796179600
-
1
tz.transition 1995, 9, :o2, 811904400
-
1
tz.transition 1996, 3, :o3, 828234000
-
1
tz.transition 1996, 10, :o2, 846378000
-
1
tz.transition 1997, 3, :o3, 859683600
-
1
tz.transition 1997, 10, :o2, 877827600
-
1
tz.transition 1998, 3, :o3, 891133200
-
1
tz.transition 1998, 10, :o2, 909277200
-
1
tz.transition 1999, 3, :o3, 922582800
-
1
tz.transition 1999, 10, :o2, 941331600
-
1
tz.transition 2000, 3, :o3, 954032400
-
1
tz.transition 2000, 10, :o2, 972781200
-
1
tz.transition 2001, 3, :o3, 985482000
-
1
tz.transition 2001, 10, :o2, 1004230800
-
1
tz.transition 2002, 3, :o3, 1017536400
-
1
tz.transition 2002, 10, :o2, 1035680400
-
1
tz.transition 2003, 3, :o3, 1048986000
-
1
tz.transition 2003, 10, :o2, 1067130000
-
1
tz.transition 2004, 3, :o3, 1080435600
-
1
tz.transition 2004, 10, :o2, 1099184400
-
1
tz.transition 2005, 3, :o3, 1111885200
-
1
tz.transition 2005, 10, :o2, 1130634000
-
1
tz.transition 2006, 3, :o3, 1143334800
-
1
tz.transition 2006, 10, :o2, 1162083600
-
1
tz.transition 2007, 3, :o3, 1174784400
-
1
tz.transition 2007, 10, :o2, 1193533200
-
1
tz.transition 2008, 3, :o3, 1206838800
-
1
tz.transition 2008, 10, :o2, 1224982800
-
1
tz.transition 2009, 3, :o3, 1238288400
-
1
tz.transition 2009, 10, :o2, 1256432400
-
1
tz.transition 2010, 3, :o3, 1269738000
-
1
tz.transition 2010, 10, :o2, 1288486800
-
1
tz.transition 2011, 3, :o3, 1301187600
-
1
tz.transition 2011, 10, :o2, 1319936400
-
1
tz.transition 2012, 3, :o3, 1332637200
-
1
tz.transition 2012, 10, :o2, 1351386000
-
1
tz.transition 2013, 3, :o3, 1364691600
-
1
tz.transition 2013, 10, :o2, 1382835600
-
1
tz.transition 2014, 3, :o3, 1396141200
-
1
tz.transition 2014, 10, :o2, 1414285200
-
1
tz.transition 2015, 3, :o3, 1427590800
-
1
tz.transition 2015, 10, :o2, 1445734800
-
1
tz.transition 2016, 3, :o3, 1459040400
-
1
tz.transition 2016, 10, :o2, 1477789200
-
1
tz.transition 2017, 3, :o3, 1490490000
-
1
tz.transition 2017, 10, :o2, 1509238800
-
1
tz.transition 2018, 3, :o3, 1521939600
-
1
tz.transition 2018, 10, :o2, 1540688400
-
1
tz.transition 2019, 3, :o3, 1553994000
-
1
tz.transition 2019, 10, :o2, 1572138000
-
1
tz.transition 2020, 3, :o3, 1585443600
-
1
tz.transition 2020, 10, :o2, 1603587600
-
1
tz.transition 2021, 3, :o3, 1616893200
-
1
tz.transition 2021, 10, :o2, 1635642000
-
1
tz.transition 2022, 3, :o3, 1648342800
-
1
tz.transition 2022, 10, :o2, 1667091600
-
1
tz.transition 2023, 3, :o3, 1679792400
-
1
tz.transition 2023, 10, :o2, 1698541200
-
1
tz.transition 2024, 3, :o3, 1711846800
-
1
tz.transition 2024, 10, :o2, 1729990800
-
1
tz.transition 2025, 3, :o3, 1743296400
-
1
tz.transition 2025, 10, :o2, 1761440400
-
1
tz.transition 2026, 3, :o3, 1774746000
-
1
tz.transition 2026, 10, :o2, 1792890000
-
1
tz.transition 2027, 3, :o3, 1806195600
-
1
tz.transition 2027, 10, :o2, 1824944400
-
1
tz.transition 2028, 3, :o3, 1837645200
-
1
tz.transition 2028, 10, :o2, 1856394000
-
1
tz.transition 2029, 3, :o3, 1869094800
-
1
tz.transition 2029, 10, :o2, 1887843600
-
1
tz.transition 2030, 3, :o3, 1901149200
-
1
tz.transition 2030, 10, :o2, 1919293200
-
1
tz.transition 2031, 3, :o3, 1932598800
-
1
tz.transition 2031, 10, :o2, 1950742800
-
1
tz.transition 2032, 3, :o3, 1964048400
-
1
tz.transition 2032, 10, :o2, 1982797200
-
1
tz.transition 2033, 3, :o3, 1995498000
-
1
tz.transition 2033, 10, :o2, 2014246800
-
1
tz.transition 2034, 3, :o3, 2026947600
-
1
tz.transition 2034, 10, :o2, 2045696400
-
1
tz.transition 2035, 3, :o3, 2058397200
-
1
tz.transition 2035, 10, :o2, 2077146000
-
1
tz.transition 2036, 3, :o3, 2090451600
-
1
tz.transition 2036, 10, :o2, 2108595600
-
1
tz.transition 2037, 3, :o3, 2121901200
-
1
tz.transition 2037, 10, :o2, 2140045200
-
1
tz.transition 2038, 3, :o3, 59172253, 24
-
1
tz.transition 2038, 10, :o2, 59177461, 24
-
1
tz.transition 2039, 3, :o3, 59180989, 24
-
1
tz.transition 2039, 10, :o2, 59186197, 24
-
1
tz.transition 2040, 3, :o3, 59189725, 24
-
1
tz.transition 2040, 10, :o2, 59194933, 24
-
1
tz.transition 2041, 3, :o3, 59198629, 24
-
1
tz.transition 2041, 10, :o2, 59203669, 24
-
1
tz.transition 2042, 3, :o3, 59207365, 24
-
1
tz.transition 2042, 10, :o2, 59212405, 24
-
1
tz.transition 2043, 3, :o3, 59216101, 24
-
1
tz.transition 2043, 10, :o2, 59221141, 24
-
1
tz.transition 2044, 3, :o3, 59224837, 24
-
1
tz.transition 2044, 10, :o2, 59230045, 24
-
1
tz.transition 2045, 3, :o3, 59233573, 24
-
1
tz.transition 2045, 10, :o2, 59238781, 24
-
1
tz.transition 2046, 3, :o3, 59242309, 24
-
1
tz.transition 2046, 10, :o2, 59247517, 24
-
1
tz.transition 2047, 3, :o3, 59251213, 24
-
1
tz.transition 2047, 10, :o2, 59256253, 24
-
1
tz.transition 2048, 3, :o3, 59259949, 24
-
1
tz.transition 2048, 10, :o2, 59264989, 24
-
1
tz.transition 2049, 3, :o3, 59268685, 24
-
1
tz.transition 2049, 10, :o2, 59273893, 24
-
1
tz.transition 2050, 3, :o3, 59277421, 24
-
1
tz.transition 2050, 10, :o2, 59282629, 24
-
end
-
end
-
end
-
end
-
end
-
1
module TZInfo
-
1
module Definitions
-
1
module Europe
-
1
module Tallinn
-
1
include TimezoneDefinition
-
-
1
timezone 'Europe/Tallinn' do |tz|
-
1
tz.offset :o0, 5940, 0, :LMT
-
1
tz.offset :o1, 5940, 0, :TMT
-
1
tz.offset :o2, 3600, 0, :CET
-
1
tz.offset :o3, 3600, 3600, :CEST
-
1
tz.offset :o4, 7200, 0, :EET
-
1
tz.offset :o5, 10800, 0, :MSK
-
1
tz.offset :o6, 10800, 3600, :MSD
-
1
tz.offset :o7, 7200, 3600, :EEST
-
-
1
tz.transition 1879, 12, :o1, 385234469, 160
-
1
tz.transition 1918, 1, :o2, 387460069, 160
-
1
tz.transition 1918, 4, :o3, 58120765, 24
-
1
tz.transition 1918, 9, :o2, 58124461, 24
-
1
tz.transition 1919, 6, :o1, 58131371, 24
-
1
tz.transition 1921, 4, :o4, 387649669, 160
-
1
tz.transition 1940, 8, :o5, 29158169, 12
-
1
tz.transition 1941, 9, :o3, 19442019, 8
-
1
tz.transition 1942, 11, :o2, 58335973, 24
-
1
tz.transition 1943, 3, :o3, 58339501, 24
-
1
tz.transition 1943, 10, :o2, 58344037, 24
-
1
tz.transition 1944, 4, :o3, 58348405, 24
-
1
tz.transition 1944, 9, :o5, 29176265, 12
-
1
tz.transition 1981, 3, :o6, 354920400
-
1
tz.transition 1981, 9, :o5, 370728000
-
1
tz.transition 1982, 3, :o6, 386456400
-
1
tz.transition 1982, 9, :o5, 402264000
-
1
tz.transition 1983, 3, :o6, 417992400
-
1
tz.transition 1983, 9, :o5, 433800000
-
1
tz.transition 1984, 3, :o6, 449614800
-
1
tz.transition 1984, 9, :o5, 465346800
-
1
tz.transition 1985, 3, :o6, 481071600
-
1
tz.transition 1985, 9, :o5, 496796400
-
1
tz.transition 1986, 3, :o6, 512521200
-
1
tz.transition 1986, 9, :o5, 528246000
-
1
tz.transition 1987, 3, :o6, 543970800
-
1
tz.transition 1987, 9, :o5, 559695600
-
1
tz.transition 1988, 3, :o6, 575420400
-
1
tz.transition 1988, 9, :o5, 591145200
-
1
tz.transition 1989, 3, :o7, 606870000
-
1
tz.transition 1989, 9, :o4, 622598400
-
1
tz.transition 1990, 3, :o7, 638323200
-
1
tz.transition 1990, 9, :o4, 654652800
-
1
tz.transition 1991, 3, :o7, 670377600
-
1
tz.transition 1991, 9, :o4, 686102400
-
1
tz.transition 1992, 3, :o7, 701827200
-
1
tz.transition 1992, 9, :o4, 717552000
-
1
tz.transition 1993, 3, :o7, 733276800
-
1
tz.transition 1993, 9, :o4, 749001600
-
1
tz.transition 1994, 3, :o7, 764726400
-
1
tz.transition 1994, 9, :o4, 780451200
-
1
tz.transition 1995, 3, :o7, 796176000
-
1
tz.transition 1995, 9, :o4, 811900800
-
1
tz.transition 1996, 3, :o7, 828230400
-
1
tz.transition 1996, 10, :o4, 846374400
-
1
tz.transition 1997, 3, :o7, 859680000
-
1
tz.transition 1997, 10, :o4, 877824000
-
1
tz.transition 1998, 3, :o7, 891129600
-
1
tz.transition 1998, 10, :o4, 909277200
-
1
tz.transition 1999, 3, :o7, 922582800
-
1
tz.transition 1999, 10, :o4, 941331600
-
1
tz.transition 2002, 3, :o7, 1017536400
-
1
tz.transition 2002, 10, :o4, 1035680400
-
1
tz.transition 2003, 3, :o7, 1048986000
-
1
tz.transition 2003, 10, :o4, 1067130000
-
1
tz.transition 2004, 3, :o7, 1080435600
-
1
tz.transition 2004, 10, :o4, 1099184400
-
1
tz.transition 2005, 3, :o7, 1111885200
-
1
tz.transition 2005, 10, :o4, 1130634000
-
1
tz.transition 2006, 3, :o7, 1143334800
-
1
tz.transition 2006, 10, :o4, 1162083600
-
1
tz.transition 2007, 3, :o7, 1174784400
-
1
tz.transition 2007, 10, :o4, 1193533200
-
1
tz.transition 2008, 3, :o7, 1206838800
-
1
tz.transition 2008, 10, :o4, 1224982800
-
1
tz.transition 2009, 3, :o7, 1238288400
-
1
tz.transition 2009, 10, :o4, 1256432400
-
1
tz.transition 2010, 3, :o7, 1269738000
-
1
tz.transition 2010, 10, :o4, 1288486800
-
1
tz.transition 2011, 3, :o7, 1301187600
-
1
tz.transition 2011, 10, :o4, 1319936400
-
1
tz.transition 2012, 3, :o7, 1332637200
-
1
tz.transition 2012, 10, :o4, 1351386000
-
1
tz.transition 2013, 3, :o7, 1364691600
-
1
tz.transition 2013, 10, :o4, 1382835600
-
1
tz.transition 2014, 3, :o7, 1396141200
-
1
tz.transition 2014, 10, :o4, 1414285200
-
1
tz.transition 2015, 3, :o7, 1427590800
-
1
tz.transition 2015, 10, :o4, 1445734800
-
1
tz.transition 2016, 3, :o7, 1459040400
-
1
tz.transition 2016, 10, :o4, 1477789200
-
1
tz.transition 2017, 3, :o7, 1490490000
-
1
tz.transition 2017, 10, :o4, 1509238800
-
1
tz.transition 2018, 3, :o7, 1521939600
-
1
tz.transition 2018, 10, :o4, 1540688400
-
1
tz.transition 2019, 3, :o7, 1553994000
-
1
tz.transition 2019, 10, :o4, 1572138000
-
1
tz.transition 2020, 3, :o7, 1585443600
-
1
tz.transition 2020, 10, :o4, 1603587600
-
1
tz.transition 2021, 3, :o7, 1616893200
-
1
tz.transition 2021, 10, :o4, 1635642000
-
1
tz.transition 2022, 3, :o7, 1648342800
-
1
tz.transition 2022, 10, :o4, 1667091600
-
1
tz.transition 2023, 3, :o7, 1679792400
-
1
tz.transition 2023, 10, :o4, 1698541200
-
1
tz.transition 2024, 3, :o7, 1711846800
-
1
tz.transition 2024, 10, :o4, 1729990800
-
1
tz.transition 2025, 3, :o7, 1743296400
-
1
tz.transition 2025, 10, :o4, 1761440400
-
1
tz.transition 2026, 3, :o7, 1774746000
-
1
tz.transition 2026, 10, :o4, 1792890000
-
1
tz.transition 2027, 3, :o7, 1806195600
-
1
tz.transition 2027, 10, :o4, 1824944400
-
1
tz.transition 2028, 3, :o7, 1837645200
-
1
tz.transition 2028, 10, :o4, 1856394000
-
1
tz.transition 2029, 3, :o7, 1869094800
-
1
tz.transition 2029, 10, :o4, 1887843600
-
1
tz.transition 2030, 3, :o7, 1901149200
-
1
tz.transition 2030, 10, :o4, 1919293200
-
1
tz.transition 2031, 3, :o7, 1932598800
-
1
tz.transition 2031, 10, :o4, 1950742800
-
1
tz.transition 2032, 3, :o7, 1964048400
-
1
tz.transition 2032, 10, :o4, 1982797200
-
1
tz.transition 2033, 3, :o7, 1995498000
-
1
tz.transition 2033, 10, :o4, 2014246800
-
1
tz.transition 2034, 3, :o7, 2026947600
-
1
tz.transition 2034, 10, :o4, 2045696400
-
1
tz.transition 2035, 3, :o7, 2058397200
-
1
tz.transition 2035, 10, :o4, 2077146000
-
1
tz.transition 2036, 3, :o7, 2090451600
-
1
tz.transition 2036, 10, :o4, 2108595600
-
1
tz.transition 2037, 3, :o7, 2121901200
-
1
tz.transition 2037, 10, :o4, 2140045200
-
1
tz.transition 2038, 3, :o7, 59172253, 24
-
1
tz.transition 2038, 10, :o4, 59177461, 24
-
1
tz.transition 2039, 3, :o7, 59180989, 24
-
1
tz.transition 2039, 10, :o4, 59186197, 24
-
1
tz.transition 2040, 3, :o7, 59189725, 24
-
1
tz.transition 2040, 10, :o4, 59194933, 24
-
1
tz.transition 2041, 3, :o7, 59198629, 24
-
1
tz.transition 2041, 10, :o4, 59203669, 24
-
1
tz.transition 2042, 3, :o7, 59207365, 24
-
1
tz.transition 2042, 10, :o4, 59212405, 24
-
1
tz.transition 2043, 3, :o7, 59216101, 24
-
1
tz.transition 2043, 10, :o4, 59221141, 24
-
1
tz.transition 2044, 3, :o7, 59224837, 24
-
1
tz.transition 2044, 10, :o4, 59230045, 24
-
1
tz.transition 2045, 3, :o7, 59233573, 24
-
1
tz.transition 2045, 10, :o4, 59238781, 24
-
1
tz.transition 2046, 3, :o7, 59242309, 24
-
1
tz.transition 2046, 10, :o4, 59247517, 24
-
1
tz.transition 2047, 3, :o7, 59251213, 24
-
1
tz.transition 2047, 10, :o4, 59256253, 24
-
1
tz.transition 2048, 3, :o7, 59259949, 24
-
1
tz.transition 2048, 10, :o4, 59264989, 24
-
1
tz.transition 2049, 3, :o7, 59268685, 24
-
1
tz.transition 2049, 10, :o4, 59273893, 24
-
1
tz.transition 2050, 3, :o7, 59277421, 24
-
1
tz.transition 2050, 10, :o4, 59282629, 24
-
end
-
end
-
end
-
end
-
end
-
1
module TZInfo
-
1
module Definitions
-
1
module Europe
-
1
module Vienna
-
1
include TimezoneDefinition
-
-
1
timezone 'Europe/Vienna' do |tz|
-
1
tz.offset :o0, 3920, 0, :LMT
-
1
tz.offset :o1, 3600, 0, :CET
-
1
tz.offset :o2, 3600, 3600, :CEST
-
-
1
tz.transition 1893, 3, :o1, 2605558811, 1080
-
1
tz.transition 1916, 4, :o2, 29051813, 12
-
1
tz.transition 1916, 9, :o1, 58107299, 24
-
1
tz.transition 1917, 4, :o2, 58112029, 24
-
1
tz.transition 1917, 9, :o1, 58115725, 24
-
1
tz.transition 1918, 4, :o2, 58120765, 24
-
1
tz.transition 1918, 9, :o1, 58124461, 24
-
1
tz.transition 1920, 4, :o2, 58138069, 24
-
1
tz.transition 1920, 9, :o1, 58141933, 24
-
1
tz.transition 1940, 4, :o2, 58313293, 24
-
1
tz.transition 1942, 11, :o1, 58335973, 24
-
1
tz.transition 1943, 3, :o2, 58339501, 24
-
1
tz.transition 1943, 10, :o1, 58344037, 24
-
1
tz.transition 1944, 4, :o2, 58348405, 24
-
1
tz.transition 1944, 10, :o1, 58352773, 24
-
1
tz.transition 1945, 4, :o2, 58357141, 24
-
1
tz.transition 1945, 4, :o1, 58357381, 24
-
1
tz.transition 1946, 4, :o2, 58366189, 24
-
1
tz.transition 1946, 10, :o1, 58370389, 24
-
1
tz.transition 1947, 4, :o2, 58374757, 24
-
1
tz.transition 1947, 10, :o1, 58379125, 24
-
1
tz.transition 1948, 4, :o2, 58383829, 24
-
1
tz.transition 1948, 10, :o1, 58387861, 24
-
1
tz.transition 1980, 4, :o2, 323823600
-
1
tz.transition 1980, 9, :o1, 338940000
-
1
tz.transition 1981, 3, :o2, 354675600
-
1
tz.transition 1981, 9, :o1, 370400400
-
1
tz.transition 1982, 3, :o2, 386125200
-
1
tz.transition 1982, 9, :o1, 401850000
-
1
tz.transition 1983, 3, :o2, 417574800
-
1
tz.transition 1983, 9, :o1, 433299600
-
1
tz.transition 1984, 3, :o2, 449024400
-
1
tz.transition 1984, 9, :o1, 465354000
-
1
tz.transition 1985, 3, :o2, 481078800
-
1
tz.transition 1985, 9, :o1, 496803600
-
1
tz.transition 1986, 3, :o2, 512528400
-
1
tz.transition 1986, 9, :o1, 528253200
-
1
tz.transition 1987, 3, :o2, 543978000
-
1
tz.transition 1987, 9, :o1, 559702800
-
1
tz.transition 1988, 3, :o2, 575427600
-
1
tz.transition 1988, 9, :o1, 591152400
-
1
tz.transition 1989, 3, :o2, 606877200
-
1
tz.transition 1989, 9, :o1, 622602000
-
1
tz.transition 1990, 3, :o2, 638326800
-
1
tz.transition 1990, 9, :o1, 654656400
-
1
tz.transition 1991, 3, :o2, 670381200
-
1
tz.transition 1991, 9, :o1, 686106000
-
1
tz.transition 1992, 3, :o2, 701830800
-
1
tz.transition 1992, 9, :o1, 717555600
-
1
tz.transition 1993, 3, :o2, 733280400
-
1
tz.transition 1993, 9, :o1, 749005200
-
1
tz.transition 1994, 3, :o2, 764730000
-
1
tz.transition 1994, 9, :o1, 780454800
-
1
tz.transition 1995, 3, :o2, 796179600
-
1
tz.transition 1995, 9, :o1, 811904400
-
1
tz.transition 1996, 3, :o2, 828234000
-
1
tz.transition 1996, 10, :o1, 846378000
-
1
tz.transition 1997, 3, :o2, 859683600
-
1
tz.transition 1997, 10, :o1, 877827600
-
1
tz.transition 1998, 3, :o2, 891133200
-
1
tz.transition 1998, 10, :o1, 909277200
-
1
tz.transition 1999, 3, :o2, 922582800
-
1
tz.transition 1999, 10, :o1, 941331600
-
1
tz.transition 2000, 3, :o2, 954032400
-
1
tz.transition 2000, 10, :o1, 972781200
-
1
tz.transition 2001, 3, :o2, 985482000
-
1
tz.transition 2001, 10, :o1, 1004230800
-
1
tz.transition 2002, 3, :o2, 1017536400
-
1
tz.transition 2002, 10, :o1, 1035680400
-
1
tz.transition 2003, 3, :o2, 1048986000
-
1
tz.transition 2003, 10, :o1, 1067130000
-
1
tz.transition 2004, 3, :o2, 1080435600
-
1
tz.transition 2004, 10, :o1, 1099184400
-
1
tz.transition 2005, 3, :o2, 1111885200
-
1
tz.transition 2005, 10, :o1, 1130634000
-
1
tz.transition 2006, 3, :o2, 1143334800
-
1
tz.transition 2006, 10, :o1, 1162083600
-
1
tz.transition 2007, 3, :o2, 1174784400
-
1
tz.transition 2007, 10, :o1, 1193533200
-
1
tz.transition 2008, 3, :o2, 1206838800
-
1
tz.transition 2008, 10, :o1, 1224982800
-
1
tz.transition 2009, 3, :o2, 1238288400
-
1
tz.transition 2009, 10, :o1, 1256432400
-
1
tz.transition 2010, 3, :o2, 1269738000
-
1
tz.transition 2010, 10, :o1, 1288486800
-
1
tz.transition 2011, 3, :o2, 1301187600
-
1
tz.transition 2011, 10, :o1, 1319936400
-
1
tz.transition 2012, 3, :o2, 1332637200
-
1
tz.transition 2012, 10, :o1, 1351386000
-
1
tz.transition 2013, 3, :o2, 1364691600
-
1
tz.transition 2013, 10, :o1, 1382835600
-
1
tz.transition 2014, 3, :o2, 1396141200
-
1
tz.transition 2014, 10, :o1, 1414285200
-
1
tz.transition 2015, 3, :o2, 1427590800
-
1
tz.transition 2015, 10, :o1, 1445734800
-
1
tz.transition 2016, 3, :o2, 1459040400
-
1
tz.transition 2016, 10, :o1, 1477789200
-
1
tz.transition 2017, 3, :o2, 1490490000
-
1
tz.transition 2017, 10, :o1, 1509238800
-
1
tz.transition 2018, 3, :o2, 1521939600
-
1
tz.transition 2018, 10, :o1, 1540688400
-
1
tz.transition 2019, 3, :o2, 1553994000
-
1
tz.transition 2019, 10, :o1, 1572138000
-
1
tz.transition 2020, 3, :o2, 1585443600
-
1
tz.transition 2020, 10, :o1, 1603587600
-
1
tz.transition 2021, 3, :o2, 1616893200
-
1
tz.transition 2021, 10, :o1, 1635642000
-
1
tz.transition 2022, 3, :o2, 1648342800
-
1
tz.transition 2022, 10, :o1, 1667091600
-
1
tz.transition 2023, 3, :o2, 1679792400
-
1
tz.transition 2023, 10, :o1, 1698541200
-
1
tz.transition 2024, 3, :o2, 1711846800
-
1
tz.transition 2024, 10, :o1, 1729990800
-
1
tz.transition 2025, 3, :o2, 1743296400
-
1
tz.transition 2025, 10, :o1, 1761440400
-
1
tz.transition 2026, 3, :o2, 1774746000
-
1
tz.transition 2026, 10, :o1, 1792890000
-
1
tz.transition 2027, 3, :o2, 1806195600
-
1
tz.transition 2027, 10, :o1, 1824944400
-
1
tz.transition 2028, 3, :o2, 1837645200
-
1
tz.transition 2028, 10, :o1, 1856394000
-
1
tz.transition 2029, 3, :o2, 1869094800
-
1
tz.transition 2029, 10, :o1, 1887843600
-
1
tz.transition 2030, 3, :o2, 1901149200
-
1
tz.transition 2030, 10, :o1, 1919293200
-
1
tz.transition 2031, 3, :o2, 1932598800
-
1
tz.transition 2031, 10, :o1, 1950742800
-
1
tz.transition 2032, 3, :o2, 1964048400
-
1
tz.transition 2032, 10, :o1, 1982797200
-
1
tz.transition 2033, 3, :o2, 1995498000
-
1
tz.transition 2033, 10, :o1, 2014246800
-
1
tz.transition 2034, 3, :o2, 2026947600
-
1
tz.transition 2034, 10, :o1, 2045696400
-
1
tz.transition 2035, 3, :o2, 2058397200
-
1
tz.transition 2035, 10, :o1, 2077146000
-
1
tz.transition 2036, 3, :o2, 2090451600
-
1
tz.transition 2036, 10, :o1, 2108595600
-
1
tz.transition 2037, 3, :o2, 2121901200
-
1
tz.transition 2037, 10, :o1, 2140045200
-
1
tz.transition 2038, 3, :o2, 59172253, 24
-
1
tz.transition 2038, 10, :o1, 59177461, 24
-
1
tz.transition 2039, 3, :o2, 59180989, 24
-
1
tz.transition 2039, 10, :o1, 59186197, 24
-
1
tz.transition 2040, 3, :o2, 59189725, 24
-
1
tz.transition 2040, 10, :o1, 59194933, 24
-
1
tz.transition 2041, 3, :o2, 59198629, 24
-
1
tz.transition 2041, 10, :o1, 59203669, 24
-
1
tz.transition 2042, 3, :o2, 59207365, 24
-
1
tz.transition 2042, 10, :o1, 59212405, 24
-
1
tz.transition 2043, 3, :o2, 59216101, 24
-
1
tz.transition 2043, 10, :o1, 59221141, 24
-
1
tz.transition 2044, 3, :o2, 59224837, 24
-
1
tz.transition 2044, 10, :o1, 59230045, 24
-
1
tz.transition 2045, 3, :o2, 59233573, 24
-
1
tz.transition 2045, 10, :o1, 59238781, 24
-
1
tz.transition 2046, 3, :o2, 59242309, 24
-
1
tz.transition 2046, 10, :o1, 59247517, 24
-
1
tz.transition 2047, 3, :o2, 59251213, 24
-
1
tz.transition 2047, 10, :o1, 59256253, 24
-
1
tz.transition 2048, 3, :o2, 59259949, 24
-
1
tz.transition 2048, 10, :o1, 59264989, 24
-
1
tz.transition 2049, 3, :o2, 59268685, 24
-
1
tz.transition 2049, 10, :o1, 59273893, 24
-
1
tz.transition 2050, 3, :o2, 59277421, 24
-
1
tz.transition 2050, 10, :o1, 59282629, 24
-
end
-
end
-
end
-
end
-
end
-
1
module TZInfo
-
1
module Definitions
-
1
module Europe
-
1
module Vilnius
-
1
include TimezoneDefinition
-
-
1
timezone 'Europe/Vilnius' do |tz|
-
1
tz.offset :o0, 6076, 0, :LMT
-
1
tz.offset :o1, 5040, 0, :WMT
-
1
tz.offset :o2, 5736, 0, :KMT
-
1
tz.offset :o3, 3600, 0, :CET
-
1
tz.offset :o4, 7200, 0, :EET
-
1
tz.offset :o5, 10800, 0, :MSK
-
1
tz.offset :o6, 3600, 3600, :CEST
-
1
tz.offset :o7, 10800, 3600, :MSD
-
1
tz.offset :o8, 7200, 3600, :EEST
-
-
1
tz.transition 1879, 12, :o1, 52006653281, 21600
-
1
tz.transition 1916, 12, :o2, 290547533, 120
-
1
tz.transition 1919, 10, :o3, 8720069161, 3600
-
1
tz.transition 1920, 7, :o4, 58140419, 24
-
1
tz.transition 1920, 10, :o3, 29071277, 12
-
1
tz.transition 1940, 8, :o5, 58316267, 24
-
1
tz.transition 1941, 6, :o6, 19441355, 8
-
1
tz.transition 1942, 11, :o3, 58335973, 24
-
1
tz.transition 1943, 3, :o6, 58339501, 24
-
1
tz.transition 1943, 10, :o3, 58344037, 24
-
1
tz.transition 1944, 4, :o6, 58348405, 24
-
1
tz.transition 1944, 7, :o5, 29175641, 12
-
1
tz.transition 1981, 3, :o7, 354920400
-
1
tz.transition 1981, 9, :o5, 370728000
-
1
tz.transition 1982, 3, :o7, 386456400
-
1
tz.transition 1982, 9, :o5, 402264000
-
1
tz.transition 1983, 3, :o7, 417992400
-
1
tz.transition 1983, 9, :o5, 433800000
-
1
tz.transition 1984, 3, :o7, 449614800
-
1
tz.transition 1984, 9, :o5, 465346800
-
1
tz.transition 1985, 3, :o7, 481071600
-
1
tz.transition 1985, 9, :o5, 496796400
-
1
tz.transition 1986, 3, :o7, 512521200
-
1
tz.transition 1986, 9, :o5, 528246000
-
1
tz.transition 1987, 3, :o7, 543970800
-
1
tz.transition 1987, 9, :o5, 559695600
-
1
tz.transition 1988, 3, :o7, 575420400
-
1
tz.transition 1988, 9, :o5, 591145200
-
1
tz.transition 1989, 3, :o7, 606870000
-
1
tz.transition 1989, 9, :o5, 622594800
-
1
tz.transition 1990, 3, :o7, 638319600
-
1
tz.transition 1990, 9, :o5, 654649200
-
1
tz.transition 1991, 3, :o8, 670374000
-
1
tz.transition 1991, 9, :o4, 686102400
-
1
tz.transition 1992, 3, :o8, 701827200
-
1
tz.transition 1992, 9, :o4, 717552000
-
1
tz.transition 1993, 3, :o8, 733276800
-
1
tz.transition 1993, 9, :o4, 749001600
-
1
tz.transition 1994, 3, :o8, 764726400
-
1
tz.transition 1994, 9, :o4, 780451200
-
1
tz.transition 1995, 3, :o8, 796176000
-
1
tz.transition 1995, 9, :o4, 811900800
-
1
tz.transition 1996, 3, :o8, 828230400
-
1
tz.transition 1996, 10, :o4, 846374400
-
1
tz.transition 1997, 3, :o8, 859680000
-
1
tz.transition 1997, 10, :o4, 877824000
-
1
tz.transition 1998, 3, :o6, 891133200
-
1
tz.transition 1998, 10, :o3, 909277200
-
1
tz.transition 1999, 3, :o6, 922582800
-
1
tz.transition 1999, 10, :o4, 941331600
-
1
tz.transition 2003, 3, :o8, 1048986000
-
1
tz.transition 2003, 10, :o4, 1067130000
-
1
tz.transition 2004, 3, :o8, 1080435600
-
1
tz.transition 2004, 10, :o4, 1099184400
-
1
tz.transition 2005, 3, :o8, 1111885200
-
1
tz.transition 2005, 10, :o4, 1130634000
-
1
tz.transition 2006, 3, :o8, 1143334800
-
1
tz.transition 2006, 10, :o4, 1162083600
-
1
tz.transition 2007, 3, :o8, 1174784400
-
1
tz.transition 2007, 10, :o4, 1193533200
-
1
tz.transition 2008, 3, :o8, 1206838800
-
1
tz.transition 2008, 10, :o4, 1224982800
-
1
tz.transition 2009, 3, :o8, 1238288400
-
1
tz.transition 2009, 10, :o4, 1256432400
-
1
tz.transition 2010, 3, :o8, 1269738000
-
1
tz.transition 2010, 10, :o4, 1288486800
-
1
tz.transition 2011, 3, :o8, 1301187600
-
1
tz.transition 2011, 10, :o4, 1319936400
-
1
tz.transition 2012, 3, :o8, 1332637200
-
1
tz.transition 2012, 10, :o4, 1351386000
-
1
tz.transition 2013, 3, :o8, 1364691600
-
1
tz.transition 2013, 10, :o4, 1382835600
-
1
tz.transition 2014, 3, :o8, 1396141200
-
1
tz.transition 2014, 10, :o4, 1414285200
-
1
tz.transition 2015, 3, :o8, 1427590800
-
1
tz.transition 2015, 10, :o4, 1445734800
-
1
tz.transition 2016, 3, :o8, 1459040400
-
1
tz.transition 2016, 10, :o4, 1477789200
-
1
tz.transition 2017, 3, :o8, 1490490000
-
1
tz.transition 2017, 10, :o4, 1509238800
-
1
tz.transition 2018, 3, :o8, 1521939600
-
1
tz.transition 2018, 10, :o4, 1540688400
-
1
tz.transition 2019, 3, :o8, 1553994000
-
1
tz.transition 2019, 10, :o4, 1572138000
-
1
tz.transition 2020, 3, :o8, 1585443600
-
1
tz.transition 2020, 10, :o4, 1603587600
-
1
tz.transition 2021, 3, :o8, 1616893200
-
1
tz.transition 2021, 10, :o4, 1635642000
-
1
tz.transition 2022, 3, :o8, 1648342800
-
1
tz.transition 2022, 10, :o4, 1667091600
-
1
tz.transition 2023, 3, :o8, 1679792400
-
1
tz.transition 2023, 10, :o4, 1698541200
-
1
tz.transition 2024, 3, :o8, 1711846800
-
1
tz.transition 2024, 10, :o4, 1729990800
-
1
tz.transition 2025, 3, :o8, 1743296400
-
1
tz.transition 2025, 10, :o4, 1761440400
-
1
tz.transition 2026, 3, :o8, 1774746000
-
1
tz.transition 2026, 10, :o4, 1792890000
-
1
tz.transition 2027, 3, :o8, 1806195600
-
1
tz.transition 2027, 10, :o4, 1824944400
-
1
tz.transition 2028, 3, :o8, 1837645200
-
1
tz.transition 2028, 10, :o4, 1856394000
-
1
tz.transition 2029, 3, :o8, 1869094800
-
1
tz.transition 2029, 10, :o4, 1887843600
-
1
tz.transition 2030, 3, :o8, 1901149200
-
1
tz.transition 2030, 10, :o4, 1919293200
-
1
tz.transition 2031, 3, :o8, 1932598800
-
1
tz.transition 2031, 10, :o4, 1950742800
-
1
tz.transition 2032, 3, :o8, 1964048400
-
1
tz.transition 2032, 10, :o4, 1982797200
-
1
tz.transition 2033, 3, :o8, 1995498000
-
1
tz.transition 2033, 10, :o4, 2014246800
-
1
tz.transition 2034, 3, :o8, 2026947600
-
1
tz.transition 2034, 10, :o4, 2045696400
-
1
tz.transition 2035, 3, :o8, 2058397200
-
1
tz.transition 2035, 10, :o4, 2077146000
-
1
tz.transition 2036, 3, :o8, 2090451600
-
1
tz.transition 2036, 10, :o4, 2108595600
-
1
tz.transition 2037, 3, :o8, 2121901200
-
1
tz.transition 2037, 10, :o4, 2140045200
-
1
tz.transition 2038, 3, :o8, 59172253, 24
-
1
tz.transition 2038, 10, :o4, 59177461, 24
-
1
tz.transition 2039, 3, :o8, 59180989, 24
-
1
tz.transition 2039, 10, :o4, 59186197, 24
-
1
tz.transition 2040, 3, :o8, 59189725, 24
-
1
tz.transition 2040, 10, :o4, 59194933, 24
-
1
tz.transition 2041, 3, :o8, 59198629, 24
-
1
tz.transition 2041, 10, :o4, 59203669, 24
-
1
tz.transition 2042, 3, :o8, 59207365, 24
-
1
tz.transition 2042, 10, :o4, 59212405, 24
-
1
tz.transition 2043, 3, :o8, 59216101, 24
-
1
tz.transition 2043, 10, :o4, 59221141, 24
-
1
tz.transition 2044, 3, :o8, 59224837, 24
-
1
tz.transition 2044, 10, :o4, 59230045, 24
-
1
tz.transition 2045, 3, :o8, 59233573, 24
-
1
tz.transition 2045, 10, :o4, 59238781, 24
-
1
tz.transition 2046, 3, :o8, 59242309, 24
-
1
tz.transition 2046, 10, :o4, 59247517, 24
-
1
tz.transition 2047, 3, :o8, 59251213, 24
-
1
tz.transition 2047, 10, :o4, 59256253, 24
-
1
tz.transition 2048, 3, :o8, 59259949, 24
-
1
tz.transition 2048, 10, :o4, 59264989, 24
-
1
tz.transition 2049, 3, :o8, 59268685, 24
-
1
tz.transition 2049, 10, :o4, 59273893, 24
-
1
tz.transition 2050, 3, :o8, 59277421, 24
-
1
tz.transition 2050, 10, :o4, 59282629, 24
-
end
-
end
-
end
-
end
-
end
-
1
module TZInfo
-
1
module Definitions
-
1
module Europe
-
1
module Warsaw
-
1
include TimezoneDefinition
-
-
1
timezone 'Europe/Warsaw' do |tz|
-
1
tz.offset :o0, 5040, 0, :LMT
-
1
tz.offset :o1, 5040, 0, :WMT
-
1
tz.offset :o2, 3600, 0, :CET
-
1
tz.offset :o3, 3600, 3600, :CEST
-
1
tz.offset :o4, 7200, 0, :EET
-
1
tz.offset :o5, 7200, 3600, :EEST
-
-
1
tz.transition 1879, 12, :o1, 288925853, 120
-
1
tz.transition 1915, 8, :o2, 290485733, 120
-
1
tz.transition 1916, 4, :o3, 29051813, 12
-
1
tz.transition 1916, 9, :o2, 58107299, 24
-
1
tz.transition 1917, 4, :o3, 58112029, 24
-
1
tz.transition 1917, 9, :o2, 58115725, 24
-
1
tz.transition 1918, 4, :o3, 58120765, 24
-
1
tz.transition 1918, 9, :o4, 58124461, 24
-
1
tz.transition 1919, 4, :o5, 4844127, 2
-
1
tz.transition 1919, 9, :o4, 4844435, 2
-
1
tz.transition 1922, 5, :o2, 29078477, 12
-
1
tz.transition 1940, 6, :o3, 58315285, 24
-
1
tz.transition 1942, 11, :o2, 58335973, 24
-
1
tz.transition 1943, 3, :o3, 58339501, 24
-
1
tz.transition 1943, 10, :o2, 58344037, 24
-
1
tz.transition 1944, 4, :o3, 58348405, 24
-
1
tz.transition 1944, 10, :o2, 4862735, 2
-
1
tz.transition 1945, 4, :o3, 58357787, 24
-
1
tz.transition 1945, 10, :o2, 29181125, 12
-
1
tz.transition 1946, 4, :o3, 58366187, 24
-
1
tz.transition 1946, 10, :o2, 58370413, 24
-
1
tz.transition 1947, 5, :o3, 58375429, 24
-
1
tz.transition 1947, 10, :o2, 58379125, 24
-
1
tz.transition 1948, 4, :o3, 58383829, 24
-
1
tz.transition 1948, 10, :o2, 58387861, 24
-
1
tz.transition 1949, 4, :o3, 58392397, 24
-
1
tz.transition 1949, 10, :o2, 58396597, 24
-
1
tz.transition 1957, 6, :o3, 4871983, 2
-
1
tz.transition 1957, 9, :o2, 4872221, 2
-
1
tz.transition 1958, 3, :o3, 4872585, 2
-
1
tz.transition 1958, 9, :o2, 4872949, 2
-
1
tz.transition 1959, 5, :o3, 4873439, 2
-
1
tz.transition 1959, 10, :o2, 4873691, 2
-
1
tz.transition 1960, 4, :o3, 4874055, 2
-
1
tz.transition 1960, 10, :o2, 4874419, 2
-
1
tz.transition 1961, 5, :o3, 4874895, 2
-
1
tz.transition 1961, 10, :o2, 4875147, 2
-
1
tz.transition 1962, 5, :o3, 4875623, 2
-
1
tz.transition 1962, 9, :o2, 4875875, 2
-
1
tz.transition 1963, 5, :o3, 4876351, 2
-
1
tz.transition 1963, 9, :o2, 4876603, 2
-
1
tz.transition 1964, 5, :o3, 4877093, 2
-
1
tz.transition 1964, 9, :o2, 4877331, 2
-
1
tz.transition 1977, 4, :o3, 228873600
-
1
tz.transition 1977, 9, :o2, 243993600
-
1
tz.transition 1978, 4, :o3, 260323200
-
1
tz.transition 1978, 10, :o2, 276048000
-
1
tz.transition 1979, 4, :o3, 291772800
-
1
tz.transition 1979, 9, :o2, 307497600
-
1
tz.transition 1980, 4, :o3, 323827200
-
1
tz.transition 1980, 9, :o2, 338947200
-
1
tz.transition 1981, 3, :o3, 354672000
-
1
tz.transition 1981, 9, :o2, 370396800
-
1
tz.transition 1982, 3, :o3, 386121600
-
1
tz.transition 1982, 9, :o2, 401846400
-
1
tz.transition 1983, 3, :o3, 417571200
-
1
tz.transition 1983, 9, :o2, 433296000
-
1
tz.transition 1984, 3, :o3, 449020800
-
1
tz.transition 1984, 9, :o2, 465350400
-
1
tz.transition 1985, 3, :o3, 481075200
-
1
tz.transition 1985, 9, :o2, 496800000
-
1
tz.transition 1986, 3, :o3, 512524800
-
1
tz.transition 1986, 9, :o2, 528249600
-
1
tz.transition 1987, 3, :o3, 543974400
-
1
tz.transition 1987, 9, :o2, 559699200
-
1
tz.transition 1988, 3, :o3, 575427600
-
1
tz.transition 1988, 9, :o2, 591152400
-
1
tz.transition 1989, 3, :o3, 606877200
-
1
tz.transition 1989, 9, :o2, 622602000
-
1
tz.transition 1990, 3, :o3, 638326800
-
1
tz.transition 1990, 9, :o2, 654656400
-
1
tz.transition 1991, 3, :o3, 670381200
-
1
tz.transition 1991, 9, :o2, 686106000
-
1
tz.transition 1992, 3, :o3, 701830800
-
1
tz.transition 1992, 9, :o2, 717555600
-
1
tz.transition 1993, 3, :o3, 733280400
-
1
tz.transition 1993, 9, :o2, 749005200
-
1
tz.transition 1994, 3, :o3, 764730000
-
1
tz.transition 1994, 9, :o2, 780454800
-
1
tz.transition 1995, 3, :o3, 796179600
-
1
tz.transition 1995, 9, :o2, 811904400
-
1
tz.transition 1996, 3, :o3, 828234000
-
1
tz.transition 1996, 10, :o2, 846378000
-
1
tz.transition 1997, 3, :o3, 859683600
-
1
tz.transition 1997, 10, :o2, 877827600
-
1
tz.transition 1998, 3, :o3, 891133200
-
1
tz.transition 1998, 10, :o2, 909277200
-
1
tz.transition 1999, 3, :o3, 922582800
-
1
tz.transition 1999, 10, :o2, 941331600
-
1
tz.transition 2000, 3, :o3, 954032400
-
1
tz.transition 2000, 10, :o2, 972781200
-
1
tz.transition 2001, 3, :o3, 985482000
-
1
tz.transition 2001, 10, :o2, 1004230800
-
1
tz.transition 2002, 3, :o3, 1017536400
-
1
tz.transition 2002, 10, :o2, 1035680400
-
1
tz.transition 2003, 3, :o3, 1048986000
-
1
tz.transition 2003, 10, :o2, 1067130000
-
1
tz.transition 2004, 3, :o3, 1080435600
-
1
tz.transition 2004, 10, :o2, 1099184400
-
1
tz.transition 2005, 3, :o3, 1111885200
-
1
tz.transition 2005, 10, :o2, 1130634000
-
1
tz.transition 2006, 3, :o3, 1143334800
-
1
tz.transition 2006, 10, :o2, 1162083600
-
1
tz.transition 2007, 3, :o3, 1174784400
-
1
tz.transition 2007, 10, :o2, 1193533200
-
1
tz.transition 2008, 3, :o3, 1206838800
-
1
tz.transition 2008, 10, :o2, 1224982800
-
1
tz.transition 2009, 3, :o3, 1238288400
-
1
tz.transition 2009, 10, :o2, 1256432400
-
1
tz.transition 2010, 3, :o3, 1269738000
-
1
tz.transition 2010, 10, :o2, 1288486800
-
1
tz.transition 2011, 3, :o3, 1301187600
-
1
tz.transition 2011, 10, :o2, 1319936400
-
1
tz.transition 2012, 3, :o3, 1332637200
-
1
tz.transition 2012, 10, :o2, 1351386000
-
1
tz.transition 2013, 3, :o3, 1364691600
-
1
tz.transition 2013, 10, :o2, 1382835600
-
1
tz.transition 2014, 3, :o3, 1396141200
-
1
tz.transition 2014, 10, :o2, 1414285200
-
1
tz.transition 2015, 3, :o3, 1427590800
-
1
tz.transition 2015, 10, :o2, 1445734800
-
1
tz.transition 2016, 3, :o3, 1459040400
-
1
tz.transition 2016, 10, :o2, 1477789200
-
1
tz.transition 2017, 3, :o3, 1490490000
-
1
tz.transition 2017, 10, :o2, 1509238800
-
1
tz.transition 2018, 3, :o3, 1521939600
-
1
tz.transition 2018, 10, :o2, 1540688400
-
1
tz.transition 2019, 3, :o3, 1553994000
-
1
tz.transition 2019, 10, :o2, 1572138000
-
1
tz.transition 2020, 3, :o3, 1585443600
-
1
tz.transition 2020, 10, :o2, 1603587600
-
1
tz.transition 2021, 3, :o3, 1616893200
-
1
tz.transition 2021, 10, :o2, 1635642000
-
1
tz.transition 2022, 3, :o3, 1648342800
-
1
tz.transition 2022, 10, :o2, 1667091600
-
1
tz.transition 2023, 3, :o3, 1679792400
-
1
tz.transition 2023, 10, :o2, 1698541200
-
1
tz.transition 2024, 3, :o3, 1711846800
-
1
tz.transition 2024, 10, :o2, 1729990800
-
1
tz.transition 2025, 3, :o3, 1743296400
-
1
tz.transition 2025, 10, :o2, 1761440400
-
1
tz.transition 2026, 3, :o3, 1774746000
-
1
tz.transition 2026, 10, :o2, 1792890000
-
1
tz.transition 2027, 3, :o3, 1806195600
-
1
tz.transition 2027, 10, :o2, 1824944400
-
1
tz.transition 2028, 3, :o3, 1837645200
-
1
tz.transition 2028, 10, :o2, 1856394000
-
1
tz.transition 2029, 3, :o3, 1869094800
-
1
tz.transition 2029, 10, :o2, 1887843600
-
1
tz.transition 2030, 3, :o3, 1901149200
-
1
tz.transition 2030, 10, :o2, 1919293200
-
1
tz.transition 2031, 3, :o3, 1932598800
-
1
tz.transition 2031, 10, :o2, 1950742800
-
1
tz.transition 2032, 3, :o3, 1964048400
-
1
tz.transition 2032, 10, :o2, 1982797200
-
1
tz.transition 2033, 3, :o3, 1995498000
-
1
tz.transition 2033, 10, :o2, 2014246800
-
1
tz.transition 2034, 3, :o3, 2026947600
-
1
tz.transition 2034, 10, :o2, 2045696400
-
1
tz.transition 2035, 3, :o3, 2058397200
-
1
tz.transition 2035, 10, :o2, 2077146000
-
1
tz.transition 2036, 3, :o3, 2090451600
-
1
tz.transition 2036, 10, :o2, 2108595600
-
1
tz.transition 2037, 3, :o3, 2121901200
-
1
tz.transition 2037, 10, :o2, 2140045200
-
1
tz.transition 2038, 3, :o3, 59172253, 24
-
1
tz.transition 2038, 10, :o2, 59177461, 24
-
1
tz.transition 2039, 3, :o3, 59180989, 24
-
1
tz.transition 2039, 10, :o2, 59186197, 24
-
1
tz.transition 2040, 3, :o3, 59189725, 24
-
1
tz.transition 2040, 10, :o2, 59194933, 24
-
1
tz.transition 2041, 3, :o3, 59198629, 24
-
1
tz.transition 2041, 10, :o2, 59203669, 24
-
1
tz.transition 2042, 3, :o3, 59207365, 24
-
1
tz.transition 2042, 10, :o2, 59212405, 24
-
1
tz.transition 2043, 3, :o3, 59216101, 24
-
1
tz.transition 2043, 10, :o2, 59221141, 24
-
1
tz.transition 2044, 3, :o3, 59224837, 24
-
1
tz.transition 2044, 10, :o2, 59230045, 24
-
1
tz.transition 2045, 3, :o3, 59233573, 24
-
1
tz.transition 2045, 10, :o2, 59238781, 24
-
1
tz.transition 2046, 3, :o3, 59242309, 24
-
1
tz.transition 2046, 10, :o2, 59247517, 24
-
1
tz.transition 2047, 3, :o3, 59251213, 24
-
1
tz.transition 2047, 10, :o2, 59256253, 24
-
1
tz.transition 2048, 3, :o3, 59259949, 24
-
1
tz.transition 2048, 10, :o2, 59264989, 24
-
1
tz.transition 2049, 3, :o3, 59268685, 24
-
1
tz.transition 2049, 10, :o2, 59273893, 24
-
1
tz.transition 2050, 3, :o3, 59277421, 24
-
1
tz.transition 2050, 10, :o2, 59282629, 24
-
end
-
end
-
end
-
end
-
end
-
1
module TZInfo
-
1
module Definitions
-
1
module Europe
-
1
module Zagreb
-
1
include TimezoneDefinition
-
-
1
linked_timezone 'Europe/Zagreb', 'Europe/Belgrade'
-
end
-
end
-
end
-
end
-
1
module TZInfo
-
1
module Definitions
-
1
module Pacific
-
1
module Apia
-
1
include TimezoneDefinition
-
-
1
timezone 'Pacific/Apia' do |tz|
-
1
tz.offset :o0, 45184, 0, :LMT
-
1
tz.offset :o1, -41216, 0, :LMT
-
1
tz.offset :o2, -41400, 0, :SAMT
-
1
tz.offset :o3, -39600, 0, :WST
-
1
tz.offset :o4, -39600, 3600, :WSDT
-
1
tz.offset :o5, 46800, 3600, :WSDT
-
1
tz.offset :o6, 46800, 0, :WST
-
-
1
tz.transition 1879, 7, :o1, 3250172219, 1350
-
1
tz.transition 1911, 1, :o2, 3265701269, 1350
-
1
tz.transition 1950, 1, :o3, 116797583, 48
-
1
tz.transition 2010, 9, :o4, 1285498800
-
1
tz.transition 2011, 4, :o3, 1301752800
-
1
tz.transition 2011, 9, :o4, 1316872800
-
1
tz.transition 2011, 12, :o5, 1325239200
-
1
tz.transition 2012, 3, :o6, 1333202400
-
1
tz.transition 2012, 9, :o5, 1348927200
-
1
tz.transition 2013, 4, :o6, 1365256800
-
1
tz.transition 2013, 9, :o5, 1380376800
-
1
tz.transition 2014, 4, :o6, 1396706400
-
1
tz.transition 2014, 9, :o5, 1411826400
-
1
tz.transition 2015, 4, :o6, 1428156000
-
1
tz.transition 2015, 9, :o5, 1443276000
-
1
tz.transition 2016, 4, :o6, 1459605600
-
1
tz.transition 2016, 9, :o5, 1474725600
-
1
tz.transition 2017, 4, :o6, 1491055200
-
1
tz.transition 2017, 9, :o5, 1506175200
-
1
tz.transition 2018, 3, :o6, 1522504800
-
1
tz.transition 2018, 9, :o5, 1538229600
-
1
tz.transition 2019, 4, :o6, 1554559200
-
1
tz.transition 2019, 9, :o5, 1569679200
-
1
tz.transition 2020, 4, :o6, 1586008800
-
1
tz.transition 2020, 9, :o5, 1601128800
-
1
tz.transition 2021, 4, :o6, 1617458400
-
1
tz.transition 2021, 9, :o5, 1632578400
-
1
tz.transition 2022, 4, :o6, 1648908000
-
1
tz.transition 2022, 9, :o5, 1664028000
-
1
tz.transition 2023, 4, :o6, 1680357600
-
1
tz.transition 2023, 9, :o5, 1695477600
-
1
tz.transition 2024, 4, :o6, 1712412000
-
1
tz.transition 2024, 9, :o5, 1727532000
-
1
tz.transition 2025, 4, :o6, 1743861600
-
1
tz.transition 2025, 9, :o5, 1758981600
-
1
tz.transition 2026, 4, :o6, 1775311200
-
1
tz.transition 2026, 9, :o5, 1790431200
-
1
tz.transition 2027, 4, :o6, 1806760800
-
1
tz.transition 2027, 9, :o5, 1821880800
-
1
tz.transition 2028, 4, :o6, 1838210400
-
1
tz.transition 2028, 9, :o5, 1853330400
-
1
tz.transition 2029, 3, :o6, 1869660000
-
1
tz.transition 2029, 9, :o5, 1885384800
-
1
tz.transition 2030, 4, :o6, 1901714400
-
1
tz.transition 2030, 9, :o5, 1916834400
-
1
tz.transition 2031, 4, :o6, 1933164000
-
1
tz.transition 2031, 9, :o5, 1948284000
-
1
tz.transition 2032, 4, :o6, 1964613600
-
1
tz.transition 2032, 9, :o5, 1979733600
-
1
tz.transition 2033, 4, :o6, 1996063200
-
1
tz.transition 2033, 9, :o5, 2011183200
-
1
tz.transition 2034, 4, :o6, 2027512800
-
1
tz.transition 2034, 9, :o5, 2042632800
-
1
tz.transition 2035, 3, :o6, 2058962400
-
1
tz.transition 2035, 9, :o5, 2074687200
-
1
tz.transition 2036, 4, :o6, 2091016800
-
1
tz.transition 2036, 9, :o5, 2106136800
-
1
tz.transition 2037, 4, :o6, 2122466400
-
1
tz.transition 2037, 9, :o5, 2137586400
-
1
tz.transition 2038, 4, :o6, 29586205, 12
-
1
tz.transition 2038, 9, :o5, 29588305, 12
-
1
tz.transition 2039, 4, :o6, 29590573, 12
-
1
tz.transition 2039, 9, :o5, 29592673, 12
-
1
tz.transition 2040, 3, :o6, 29594941, 12
-
1
tz.transition 2040, 9, :o5, 29597125, 12
-
1
tz.transition 2041, 4, :o6, 29599393, 12
-
1
tz.transition 2041, 9, :o5, 29601493, 12
-
1
tz.transition 2042, 4, :o6, 29603761, 12
-
1
tz.transition 2042, 9, :o5, 29605861, 12
-
1
tz.transition 2043, 4, :o6, 29608129, 12
-
1
tz.transition 2043, 9, :o5, 29610229, 12
-
1
tz.transition 2044, 4, :o6, 29612497, 12
-
1
tz.transition 2044, 9, :o5, 29614597, 12
-
1
tz.transition 2045, 4, :o6, 29616865, 12
-
1
tz.transition 2045, 9, :o5, 29618965, 12
-
1
tz.transition 2046, 3, :o6, 29621233, 12
-
1
tz.transition 2046, 9, :o5, 29623417, 12
-
1
tz.transition 2047, 4, :o6, 29625685, 12
-
1
tz.transition 2047, 9, :o5, 29627785, 12
-
1
tz.transition 2048, 4, :o6, 29630053, 12
-
1
tz.transition 2048, 9, :o5, 29632153, 12
-
1
tz.transition 2049, 4, :o6, 29634421, 12
-
1
tz.transition 2049, 9, :o5, 29636521, 12
-
1
tz.transition 2050, 4, :o6, 29638789, 12
-
end
-
end
-
end
-
end
-
end
-
1
module TZInfo
-
1
module Definitions
-
1
module Pacific
-
1
module Auckland
-
1
include TimezoneDefinition
-
-
1
timezone 'Pacific/Auckland' do |tz|
-
1
tz.offset :o0, 41944, 0, :LMT
-
1
tz.offset :o1, 41400, 0, :NZMT
-
1
tz.offset :o2, 41400, 3600, :NZST
-
1
tz.offset :o3, 41400, 1800, :NZST
-
1
tz.offset :o4, 43200, 0, :NZST
-
1
tz.offset :o5, 43200, 3600, :NZDT
-
-
1
tz.transition 1868, 11, :o1, 25959290557, 10800
-
1
tz.transition 1927, 11, :o2, 116409125, 48
-
1
tz.transition 1928, 3, :o1, 38804945, 16
-
1
tz.transition 1928, 10, :o3, 116425589, 48
-
1
tz.transition 1929, 3, :o1, 29108245, 12
-
1
tz.transition 1929, 10, :o3, 116443061, 48
-
1
tz.transition 1930, 3, :o1, 29112613, 12
-
1
tz.transition 1930, 10, :o3, 116460533, 48
-
1
tz.transition 1931, 3, :o1, 29116981, 12
-
1
tz.transition 1931, 10, :o3, 116478005, 48
-
1
tz.transition 1932, 3, :o1, 29121433, 12
-
1
tz.transition 1932, 10, :o3, 116495477, 48
-
1
tz.transition 1933, 3, :o1, 29125801, 12
-
1
tz.transition 1933, 10, :o3, 116512949, 48
-
1
tz.transition 1934, 4, :o1, 29130673, 12
-
1
tz.transition 1934, 9, :o3, 116530085, 48
-
1
tz.transition 1935, 4, :o1, 29135041, 12
-
1
tz.transition 1935, 9, :o3, 116547557, 48
-
1
tz.transition 1936, 4, :o1, 29139409, 12
-
1
tz.transition 1936, 9, :o3, 116565029, 48
-
1
tz.transition 1937, 4, :o1, 29143777, 12
-
1
tz.transition 1937, 9, :o3, 116582501, 48
-
1
tz.transition 1938, 4, :o1, 29148145, 12
-
1
tz.transition 1938, 9, :o3, 116599973, 48
-
1
tz.transition 1939, 4, :o1, 29152597, 12
-
1
tz.transition 1939, 9, :o3, 116617445, 48
-
1
tz.transition 1940, 4, :o1, 29156965, 12
-
1
tz.transition 1940, 9, :o3, 116635253, 48
-
1
tz.transition 1945, 12, :o4, 2431821, 1
-
1
tz.transition 1974, 11, :o5, 152632800
-
1
tz.transition 1975, 2, :o4, 162309600
-
1
tz.transition 1975, 10, :o5, 183477600
-
1
tz.transition 1976, 3, :o4, 194968800
-
1
tz.transition 1976, 10, :o5, 215532000
-
1
tz.transition 1977, 3, :o4, 226418400
-
1
tz.transition 1977, 10, :o5, 246981600
-
1
tz.transition 1978, 3, :o4, 257868000
-
1
tz.transition 1978, 10, :o5, 278431200
-
1
tz.transition 1979, 3, :o4, 289317600
-
1
tz.transition 1979, 10, :o5, 309880800
-
1
tz.transition 1980, 3, :o4, 320767200
-
1
tz.transition 1980, 10, :o5, 341330400
-
1
tz.transition 1981, 2, :o4, 352216800
-
1
tz.transition 1981, 10, :o5, 372780000
-
1
tz.transition 1982, 3, :o4, 384271200
-
1
tz.transition 1982, 10, :o5, 404834400
-
1
tz.transition 1983, 3, :o4, 415720800
-
1
tz.transition 1983, 10, :o5, 436284000
-
1
tz.transition 1984, 3, :o4, 447170400
-
1
tz.transition 1984, 10, :o5, 467733600
-
1
tz.transition 1985, 3, :o4, 478620000
-
1
tz.transition 1985, 10, :o5, 499183200
-
1
tz.transition 1986, 3, :o4, 510069600
-
1
tz.transition 1986, 10, :o5, 530632800
-
1
tz.transition 1987, 2, :o4, 541519200
-
1
tz.transition 1987, 10, :o5, 562082400
-
1
tz.transition 1988, 3, :o4, 573573600
-
1
tz.transition 1988, 10, :o5, 594136800
-
1
tz.transition 1989, 3, :o4, 605023200
-
1
tz.transition 1989, 10, :o5, 623772000
-
1
tz.transition 1990, 3, :o4, 637682400
-
1
tz.transition 1990, 10, :o5, 655221600
-
1
tz.transition 1991, 3, :o4, 669132000
-
1
tz.transition 1991, 10, :o5, 686671200
-
1
tz.transition 1992, 3, :o4, 700581600
-
1
tz.transition 1992, 10, :o5, 718120800
-
1
tz.transition 1993, 3, :o4, 732636000
-
1
tz.transition 1993, 10, :o5, 749570400
-
1
tz.transition 1994, 3, :o4, 764085600
-
1
tz.transition 1994, 10, :o5, 781020000
-
1
tz.transition 1995, 3, :o4, 795535200
-
1
tz.transition 1995, 9, :o5, 812469600
-
1
tz.transition 1996, 3, :o4, 826984800
-
1
tz.transition 1996, 10, :o5, 844524000
-
1
tz.transition 1997, 3, :o4, 858434400
-
1
tz.transition 1997, 10, :o5, 875973600
-
1
tz.transition 1998, 3, :o4, 889884000
-
1
tz.transition 1998, 10, :o5, 907423200
-
1
tz.transition 1999, 3, :o4, 921938400
-
1
tz.transition 1999, 10, :o5, 938872800
-
1
tz.transition 2000, 3, :o4, 953388000
-
1
tz.transition 2000, 9, :o5, 970322400
-
1
tz.transition 2001, 3, :o4, 984837600
-
1
tz.transition 2001, 10, :o5, 1002376800
-
1
tz.transition 2002, 3, :o4, 1016287200
-
1
tz.transition 2002, 10, :o5, 1033826400
-
1
tz.transition 2003, 3, :o4, 1047736800
-
1
tz.transition 2003, 10, :o5, 1065276000
-
1
tz.transition 2004, 3, :o4, 1079791200
-
1
tz.transition 2004, 10, :o5, 1096725600
-
1
tz.transition 2005, 3, :o4, 1111240800
-
1
tz.transition 2005, 10, :o5, 1128175200
-
1
tz.transition 2006, 3, :o4, 1142690400
-
1
tz.transition 2006, 9, :o5, 1159624800
-
1
tz.transition 2007, 3, :o4, 1174140000
-
1
tz.transition 2007, 9, :o5, 1191074400
-
1
tz.transition 2008, 4, :o4, 1207404000
-
1
tz.transition 2008, 9, :o5, 1222524000
-
1
tz.transition 2009, 4, :o4, 1238853600
-
1
tz.transition 2009, 9, :o5, 1253973600
-
1
tz.transition 2010, 4, :o4, 1270303200
-
1
tz.transition 2010, 9, :o5, 1285423200
-
1
tz.transition 2011, 4, :o4, 1301752800
-
1
tz.transition 2011, 9, :o5, 1316872800
-
1
tz.transition 2012, 3, :o4, 1333202400
-
1
tz.transition 2012, 9, :o5, 1348927200
-
1
tz.transition 2013, 4, :o4, 1365256800
-
1
tz.transition 2013, 9, :o5, 1380376800
-
1
tz.transition 2014, 4, :o4, 1396706400
-
1
tz.transition 2014, 9, :o5, 1411826400
-
1
tz.transition 2015, 4, :o4, 1428156000
-
1
tz.transition 2015, 9, :o5, 1443276000
-
1
tz.transition 2016, 4, :o4, 1459605600
-
1
tz.transition 2016, 9, :o5, 1474725600
-
1
tz.transition 2017, 4, :o4, 1491055200
-
1
tz.transition 2017, 9, :o5, 1506175200
-
1
tz.transition 2018, 3, :o4, 1522504800
-
1
tz.transition 2018, 9, :o5, 1538229600
-
1
tz.transition 2019, 4, :o4, 1554559200
-
1
tz.transition 2019, 9, :o5, 1569679200
-
1
tz.transition 2020, 4, :o4, 1586008800
-
1
tz.transition 2020, 9, :o5, 1601128800
-
1
tz.transition 2021, 4, :o4, 1617458400
-
1
tz.transition 2021, 9, :o5, 1632578400
-
1
tz.transition 2022, 4, :o4, 1648908000
-
1
tz.transition 2022, 9, :o5, 1664028000
-
1
tz.transition 2023, 4, :o4, 1680357600
-
1
tz.transition 2023, 9, :o5, 1695477600
-
1
tz.transition 2024, 4, :o4, 1712412000
-
1
tz.transition 2024, 9, :o5, 1727532000
-
1
tz.transition 2025, 4, :o4, 1743861600
-
1
tz.transition 2025, 9, :o5, 1758981600
-
1
tz.transition 2026, 4, :o4, 1775311200
-
1
tz.transition 2026, 9, :o5, 1790431200
-
1
tz.transition 2027, 4, :o4, 1806760800
-
1
tz.transition 2027, 9, :o5, 1821880800
-
1
tz.transition 2028, 4, :o4, 1838210400
-
1
tz.transition 2028, 9, :o5, 1853330400
-
1
tz.transition 2029, 3, :o4, 1869660000
-
1
tz.transition 2029, 9, :o5, 1885384800
-
1
tz.transition 2030, 4, :o4, 1901714400
-
1
tz.transition 2030, 9, :o5, 1916834400
-
1
tz.transition 2031, 4, :o4, 1933164000
-
1
tz.transition 2031, 9, :o5, 1948284000
-
1
tz.transition 2032, 4, :o4, 1964613600
-
1
tz.transition 2032, 9, :o5, 1979733600
-
1
tz.transition 2033, 4, :o4, 1996063200
-
1
tz.transition 2033, 9, :o5, 2011183200
-
1
tz.transition 2034, 4, :o4, 2027512800
-
1
tz.transition 2034, 9, :o5, 2042632800
-
1
tz.transition 2035, 3, :o4, 2058962400
-
1
tz.transition 2035, 9, :o5, 2074687200
-
1
tz.transition 2036, 4, :o4, 2091016800
-
1
tz.transition 2036, 9, :o5, 2106136800
-
1
tz.transition 2037, 4, :o4, 2122466400
-
1
tz.transition 2037, 9, :o5, 2137586400
-
1
tz.transition 2038, 4, :o4, 29586205, 12
-
1
tz.transition 2038, 9, :o5, 29588305, 12
-
1
tz.transition 2039, 4, :o4, 29590573, 12
-
1
tz.transition 2039, 9, :o5, 29592673, 12
-
1
tz.transition 2040, 3, :o4, 29594941, 12
-
1
tz.transition 2040, 9, :o5, 29597125, 12
-
1
tz.transition 2041, 4, :o4, 29599393, 12
-
1
tz.transition 2041, 9, :o5, 29601493, 12
-
1
tz.transition 2042, 4, :o4, 29603761, 12
-
1
tz.transition 2042, 9, :o5, 29605861, 12
-
1
tz.transition 2043, 4, :o4, 29608129, 12
-
1
tz.transition 2043, 9, :o5, 29610229, 12
-
1
tz.transition 2044, 4, :o4, 29612497, 12
-
1
tz.transition 2044, 9, :o5, 29614597, 12
-
1
tz.transition 2045, 4, :o4, 29616865, 12
-
1
tz.transition 2045, 9, :o5, 29618965, 12
-
1
tz.transition 2046, 3, :o4, 29621233, 12
-
1
tz.transition 2046, 9, :o5, 29623417, 12
-
1
tz.transition 2047, 4, :o4, 29625685, 12
-
1
tz.transition 2047, 9, :o5, 29627785, 12
-
1
tz.transition 2048, 4, :o4, 29630053, 12
-
1
tz.transition 2048, 9, :o5, 29632153, 12
-
1
tz.transition 2049, 4, :o4, 29634421, 12
-
1
tz.transition 2049, 9, :o5, 29636521, 12
-
1
tz.transition 2050, 4, :o4, 29638789, 12
-
end
-
end
-
end
-
end
-
end
-
1
module TZInfo
-
1
module Definitions
-
1
module Pacific
-
1
module Fakaofo
-
1
include TimezoneDefinition
-
-
1
timezone 'Pacific/Fakaofo' do |tz|
-
1
tz.offset :o0, -41096, 0, :LMT
-
1
tz.offset :o1, -39600, 0, :TKT
-
1
tz.offset :o2, 46800, 0, :TKT
-
-
1
tz.transition 1901, 1, :o1, 26086168537, 10800
-
1
tz.transition 2011, 12, :o2, 1325242800
-
end
-
end
-
end
-
end
-
end
-
1
module TZInfo
-
1
module Definitions
-
1
module Pacific
-
1
module Fiji
-
1
include TimezoneDefinition
-
-
1
timezone 'Pacific/Fiji' do |tz|
-
1
tz.offset :o0, 42820, 0, :LMT
-
1
tz.offset :o1, 43200, 0, :FJT
-
1
tz.offset :o2, 43200, 3600, :FJST
-
-
1
tz.transition 1915, 10, :o1, 10457838739, 4320
-
1
tz.transition 1998, 10, :o2, 909842400
-
1
tz.transition 1999, 2, :o1, 920124000
-
1
tz.transition 1999, 11, :o2, 941896800
-
1
tz.transition 2000, 2, :o1, 951573600
-
1
tz.transition 2009, 11, :o2, 1259416800
-
1
tz.transition 2010, 3, :o1, 1269698400
-
1
tz.transition 2010, 10, :o2, 1287842400
-
1
tz.transition 2011, 3, :o1, 1299333600
-
1
tz.transition 2011, 10, :o2, 1319292000
-
1
tz.transition 2012, 1, :o1, 1327154400
-
1
tz.transition 2012, 10, :o2, 1350741600
-
1
tz.transition 2013, 1, :o1, 1358604000
-
1
tz.transition 2013, 10, :o2, 1382191200
-
1
tz.transition 2014, 1, :o1, 1390053600
-
1
tz.transition 2014, 10, :o2, 1413640800
-
1
tz.transition 2015, 1, :o1, 1421503200
-
1
tz.transition 2015, 10, :o2, 1445090400
-
1
tz.transition 2016, 1, :o1, 1453557600
-
1
tz.transition 2016, 10, :o2, 1477144800
-
1
tz.transition 2017, 1, :o1, 1485007200
-
1
tz.transition 2017, 10, :o2, 1508594400
-
1
tz.transition 2018, 1, :o1, 1516456800
-
1
tz.transition 2018, 10, :o2, 1540044000
-
1
tz.transition 2019, 1, :o1, 1547906400
-
1
tz.transition 2019, 10, :o2, 1571493600
-
1
tz.transition 2020, 1, :o1, 1579356000
-
1
tz.transition 2020, 10, :o2, 1602943200
-
1
tz.transition 2021, 1, :o1, 1611410400
-
1
tz.transition 2021, 10, :o2, 1634997600
-
1
tz.transition 2022, 1, :o1, 1642860000
-
1
tz.transition 2022, 10, :o2, 1666447200
-
1
tz.transition 2023, 1, :o1, 1674309600
-
1
tz.transition 2023, 10, :o2, 1697896800
-
1
tz.transition 2024, 1, :o1, 1705759200
-
1
tz.transition 2024, 10, :o2, 1729346400
-
1
tz.transition 2025, 1, :o1, 1737208800
-
1
tz.transition 2025, 10, :o2, 1760796000
-
1
tz.transition 2026, 1, :o1, 1768658400
-
1
tz.transition 2026, 10, :o2, 1792245600
-
1
tz.transition 2027, 1, :o1, 1800712800
-
1
tz.transition 2027, 10, :o2, 1824300000
-
1
tz.transition 2028, 1, :o1, 1832162400
-
1
tz.transition 2028, 10, :o2, 1855749600
-
1
tz.transition 2029, 1, :o1, 1863612000
-
1
tz.transition 2029, 10, :o2, 1887199200
-
1
tz.transition 2030, 1, :o1, 1895061600
-
1
tz.transition 2030, 10, :o2, 1918648800
-
1
tz.transition 2031, 1, :o1, 1926511200
-
1
tz.transition 2031, 10, :o2, 1950098400
-
1
tz.transition 2032, 1, :o1, 1957960800
-
1
tz.transition 2032, 10, :o2, 1982152800
-
1
tz.transition 2033, 1, :o1, 1990015200
-
1
tz.transition 2033, 10, :o2, 2013602400
-
1
tz.transition 2034, 1, :o1, 2021464800
-
1
tz.transition 2034, 10, :o2, 2045052000
-
1
tz.transition 2035, 1, :o1, 2052914400
-
1
tz.transition 2035, 10, :o2, 2076501600
-
1
tz.transition 2036, 1, :o1, 2084364000
-
1
tz.transition 2036, 10, :o2, 2107951200
-
1
tz.transition 2037, 1, :o1, 2115813600
-
1
tz.transition 2037, 10, :o2, 2139400800
-
1
tz.transition 2038, 1, :o1, 29585365, 12
-
1
tz.transition 2038, 10, :o2, 29588641, 12
-
1
tz.transition 2039, 1, :o1, 29589733, 12
-
1
tz.transition 2039, 10, :o2, 29593009, 12
-
1
tz.transition 2040, 1, :o1, 29594101, 12
-
1
tz.transition 2040, 10, :o2, 29597377, 12
-
1
tz.transition 2041, 1, :o1, 29598469, 12
-
1
tz.transition 2041, 10, :o2, 29601745, 12
-
1
tz.transition 2042, 1, :o1, 29602837, 12
-
1
tz.transition 2042, 10, :o2, 29606113, 12
-
1
tz.transition 2043, 1, :o1, 29607205, 12
-
1
tz.transition 2043, 10, :o2, 29610481, 12
-
1
tz.transition 2044, 1, :o1, 29611657, 12
-
1
tz.transition 2044, 10, :o2, 29614933, 12
-
1
tz.transition 2045, 1, :o1, 29616025, 12
-
1
tz.transition 2045, 10, :o2, 29619301, 12
-
1
tz.transition 2046, 1, :o1, 29620393, 12
-
1
tz.transition 2046, 10, :o2, 29623669, 12
-
1
tz.transition 2047, 1, :o1, 29624761, 12
-
1
tz.transition 2047, 10, :o2, 29628037, 12
-
1
tz.transition 2048, 1, :o1, 29629129, 12
-
1
tz.transition 2048, 10, :o2, 29632405, 12
-
1
tz.transition 2049, 1, :o1, 29633581, 12
-
1
tz.transition 2049, 10, :o2, 29636857, 12
-
1
tz.transition 2050, 1, :o1, 29637949, 12
-
end
-
end
-
end
-
end
-
end
-
1
module TZInfo
-
1
module Definitions
-
1
module Pacific
-
1
module Guadalcanal
-
1
include TimezoneDefinition
-
-
1
timezone 'Pacific/Guadalcanal' do |tz|
-
1
tz.offset :o0, 38388, 0, :LMT
-
1
tz.offset :o1, 39600, 0, :SBT
-
-
1
tz.transition 1912, 9, :o1, 17421667601, 7200
-
end
-
end
-
end
-
end
-
end
-
1
module TZInfo
-
1
module Definitions
-
1
module Pacific
-
1
module Guam
-
1
include TimezoneDefinition
-
-
1
timezone 'Pacific/Guam' do |tz|
-
1
tz.offset :o0, -51660, 0, :LMT
-
1
tz.offset :o1, 34740, 0, :LMT
-
1
tz.offset :o2, 36000, 0, :GST
-
1
tz.offset :o3, 36000, 0, :ChST
-
-
1
tz.transition 1844, 12, :o1, 1149567407, 480
-
1
tz.transition 1900, 12, :o2, 1159384847, 480
-
1
tz.transition 2000, 12, :o3, 977493600
-
end
-
end
-
end
-
end
-
end
-
1
module TZInfo
-
1
module Definitions
-
1
module Pacific
-
1
module Honolulu
-
1
include TimezoneDefinition
-
-
1
timezone 'Pacific/Honolulu' do |tz|
-
1
tz.offset :o0, -37886, 0, :LMT
-
1
tz.offset :o1, -37800, 0, :HST
-
1
tz.offset :o2, -37800, 3600, :HDT
-
1
tz.offset :o3, -36000, 0, :HST
-
-
1
tz.transition 1896, 1, :o1, 104266329343, 43200
-
1
tz.transition 1933, 4, :o2, 116505265, 48
-
1
tz.transition 1933, 5, :o1, 116506291, 48
-
1
tz.transition 1942, 2, :o2, 116659201, 48
-
1
tz.transition 1945, 9, :o1, 116722991, 48
-
1
tz.transition 1947, 6, :o3, 116752561, 48
-
end
-
end
-
end
-
end
-
end
-
1
module TZInfo
-
1
module Definitions
-
1
module Pacific
-
1
module Majuro
-
1
include TimezoneDefinition
-
-
1
timezone 'Pacific/Majuro' do |tz|
-
1
tz.offset :o0, 41088, 0, :LMT
-
1
tz.offset :o1, 39600, 0, :MHT
-
1
tz.offset :o2, 43200, 0, :MHT
-
-
1
tz.transition 1900, 12, :o1, 1086923261, 450
-
1
tz.transition 1969, 9, :o2, 58571881, 24
-
end
-
end
-
end
-
end
-
end
-
1
module TZInfo
-
1
module Definitions
-
1
module Pacific
-
1
module Midway
-
1
include TimezoneDefinition
-
-
1
timezone 'Pacific/Midway' do |tz|
-
1
tz.offset :o0, -42568, 0, :LMT
-
1
tz.offset :o1, -39600, 0, :NST
-
1
tz.offset :o2, -39600, 3600, :NDT
-
1
tz.offset :o3, -39600, 0, :BST
-
1
tz.offset :o4, -39600, 0, :SST
-
-
1
tz.transition 1901, 1, :o1, 26086168721, 10800
-
1
tz.transition 1956, 6, :o2, 58455071, 24
-
1
tz.transition 1956, 9, :o1, 29228627, 12
-
1
tz.transition 1967, 4, :o3, 58549967, 24
-
1
tz.transition 1983, 11, :o4, 439038000
-
end
-
end
-
end
-
end
-
end
-
1
module TZInfo
-
1
module Definitions
-
1
module Pacific
-
1
module Noumea
-
1
include TimezoneDefinition
-
-
1
timezone 'Pacific/Noumea' do |tz|
-
1
tz.offset :o0, 39948, 0, :LMT
-
1
tz.offset :o1, 39600, 0, :NCT
-
1
tz.offset :o2, 39600, 3600, :NCST
-
-
1
tz.transition 1912, 1, :o1, 17419781071, 7200
-
1
tz.transition 1977, 12, :o2, 250002000
-
1
tz.transition 1978, 2, :o1, 257342400
-
1
tz.transition 1978, 12, :o2, 281451600
-
1
tz.transition 1979, 2, :o1, 288878400
-
1
tz.transition 1996, 11, :o2, 849366000
-
1
tz.transition 1997, 3, :o1, 857228400
-
end
-
end
-
end
-
end
-
end
-
1
module TZInfo
-
1
module Definitions
-
1
module Pacific
-
1
module Pago_Pago
-
1
include TimezoneDefinition
-
-
1
timezone 'Pacific/Pago_Pago' do |tz|
-
1
tz.offset :o0, 45432, 0, :LMT
-
1
tz.offset :o1, -40968, 0, :LMT
-
1
tz.offset :o2, -41400, 0, :SAMT
-
1
tz.offset :o3, -39600, 0, :NST
-
1
tz.offset :o4, -39600, 0, :BST
-
1
tz.offset :o5, -39600, 0, :SST
-
-
1
tz.transition 1879, 7, :o1, 2889041969, 1200
-
1
tz.transition 1911, 1, :o2, 2902845569, 1200
-
1
tz.transition 1950, 1, :o3, 116797583, 48
-
1
tz.transition 1967, 4, :o4, 58549967, 24
-
1
tz.transition 1983, 11, :o5, 439038000
-
end
-
end
-
end
-
end
-
end
-
1
module TZInfo
-
1
module Definitions
-
1
module Pacific
-
1
module Port_Moresby
-
1
include TimezoneDefinition
-
-
1
timezone 'Pacific/Port_Moresby' do |tz|
-
1
tz.offset :o0, 35320, 0, :LMT
-
1
tz.offset :o1, 35312, 0, :PMMT
-
1
tz.offset :o2, 36000, 0, :PGT
-
-
1
tz.transition 1879, 12, :o1, 5200664597, 2160
-
1
tz.transition 1894, 12, :o2, 13031248093, 5400
-
end
-
end
-
end
-
end
-
end
-
1
module TZInfo
-
1
module Definitions
-
1
module Pacific
-
1
module Tongatapu
-
1
include TimezoneDefinition
-
-
1
timezone 'Pacific/Tongatapu' do |tz|
-
1
tz.offset :o0, 44360, 0, :LMT
-
1
tz.offset :o1, 44400, 0, :TOT
-
1
tz.offset :o2, 46800, 0, :TOT
-
1
tz.offset :o3, 46800, 3600, :TOST
-
-
1
tz.transition 1900, 12, :o1, 5217231571, 2160
-
1
tz.transition 1940, 12, :o2, 174959639, 72
-
1
tz.transition 1999, 10, :o3, 939214800
-
1
tz.transition 2000, 3, :o2, 953384400
-
1
tz.transition 2000, 11, :o3, 973342800
-
1
tz.transition 2001, 1, :o2, 980596800
-
1
tz.transition 2001, 11, :o3, 1004792400
-
1
tz.transition 2002, 1, :o2, 1012046400
-
end
-
end
-
end
-
end
-
end
-
#--
-
# Copyright (c) 2006-2010 Philip Ross
-
#
-
# Permission is hereby granted, free of charge, to any person obtaining a copy
-
# of this software and associated documentation files (the "Software"), to deal
-
# in the Software without restriction, including without limitation the rights
-
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-
# copies of the Software, and to permit persons to whom the Software is
-
# furnished to do so, subject to the following conditions:
-
#
-
# The above copyright notice and this permission notice shall be included in all
-
# copies or substantial portions of the Software.
-
#
-
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
-
# THE SOFTWARE.
-
#++
-
-
1
module TZInfo
-
-
# A Timezone based on a TimezoneInfo.
-
1
class InfoTimezone < Timezone #:nodoc:
-
-
# Constructs a new InfoTimezone with a TimezoneInfo instance.
-
1
def self.new(info)
-
127
tz = super()
-
127
tz.send(:setup, info)
-
127
tz
-
end
-
-
# The identifier of the timezone, e.g. "Europe/Paris".
-
1
def identifier
-
127
@info.identifier
-
end
-
-
1
protected
-
# The TimezoneInfo for this Timezone.
-
1
def info
-
348
@info
-
end
-
-
1
def setup(info)
-
127
@info = info
-
end
-
end
-
end
-
#--
-
# Copyright (c) 2006-2010 Philip Ross
-
#
-
# Permission is hereby granted, free of charge, to any person obtaining a copy
-
# of this software and associated documentation files (the "Software"), to deal
-
# in the Software without restriction, including without limitation the rights
-
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-
# copies of the Software, and to permit persons to whom the Software is
-
# furnished to do so, subject to the following conditions:
-
#
-
# The above copyright notice and this permission notice shall be included in all
-
# copies or substantial portions of the Software.
-
#
-
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
-
# THE SOFTWARE.
-
#++
-
-
1
module TZInfo
-
-
1
class LinkedTimezone < InfoTimezone #:nodoc:
-
# Returns the TimezonePeriod for the given UTC time. utc can either be
-
# a DateTime, Time or integer timestamp (Time.to_i). Any timezone
-
# information in utc is ignored (it is treated as a UTC time).
-
#
-
# If no TimezonePeriod could be found, PeriodNotFound is raised.
-
1
def period_for_utc(utc)
-
5
@linked_timezone.period_for_utc(utc)
-
end
-
-
# Returns the set of TimezonePeriod instances that are valid for the given
-
# local time as an array. If you just want a single period, use
-
# period_for_local instead and specify how abiguities should be resolved.
-
# Raises PeriodNotFound if no periods are found for the given time.
-
1
def periods_for_local(local)
-
@linked_timezone.periods_for_local(local)
-
end
-
-
1
protected
-
1
def setup(info)
-
5
super(info)
-
5
@linked_timezone = Timezone.get(info.link_to_identifier)
-
end
-
end
-
end
-
#--
-
# Copyright (c) 2006-2010 Philip Ross
-
#
-
# Permission is hereby granted, free of charge, to any person obtaining a copy
-
# of this software and associated documentation files (the "Software"), to deal
-
# in the Software without restriction, including without limitation the rights
-
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-
# copies of the Software, and to permit persons to whom the Software is
-
# furnished to do so, subject to the following conditions:
-
#
-
# The above copyright notice and this permission notice shall be included in all
-
# copies or substantial portions of the Software.
-
#
-
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
-
# THE SOFTWARE.
-
#++
-
-
1
module TZInfo
-
# Represents a linked timezone defined in a data module.
-
1
class LinkedTimezoneInfo < TimezoneInfo #:nodoc:
-
-
# The zone that provides the data (that this zone is an alias for).
-
1
attr_reader :link_to_identifier
-
-
# Constructs a new TimezoneInfo with an identifier and the identifier
-
# of the zone linked to.
-
1
def initialize(identifier, link_to_identifier)
-
5
super(identifier)
-
5
@link_to_identifier = link_to_identifier
-
end
-
-
# Returns internal object state as a programmer-readable string.
-
1
def inspect
-
"#<#{self.class}: #@identifier,#@link_to_identifier>"
-
end
-
end
-
end
-
#--
-
# Copyright (c) 2006-2010 Philip Ross
-
#
-
# Permission is hereby granted, free of charge, to any person obtaining a copy
-
# of this software and associated documentation files (the "Software"), to deal
-
# in the Software without restriction, including without limitation the rights
-
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-
# copies of the Software, and to permit persons to whom the Software is
-
# furnished to do so, subject to the following conditions:
-
#
-
# The above copyright notice and this permission notice shall be included in all
-
# copies or substantial portions of the Software.
-
#
-
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
-
# THE SOFTWARE.
-
#++
-
-
1
require 'rational' unless defined?(Rational)
-
-
1
module TZInfo
-
-
# Provides a method for getting Rationals for a timezone offset in seconds.
-
# Pre-reduced rationals are returned for all the half-hour intervals between
-
# -14 and +14 hours to avoid having to call gcd at runtime.
-
1
module OffsetRationals #:nodoc:
-
1
@@rational_cache = {
-
-50400 => RubyCoreSupport.rational_new!(-7,12),
-
-48600 => RubyCoreSupport.rational_new!(-9,16),
-
-46800 => RubyCoreSupport.rational_new!(-13,24),
-
-45000 => RubyCoreSupport.rational_new!(-25,48),
-
-43200 => RubyCoreSupport.rational_new!(-1,2),
-
-41400 => RubyCoreSupport.rational_new!(-23,48),
-
-39600 => RubyCoreSupport.rational_new!(-11,24),
-
-37800 => RubyCoreSupport.rational_new!(-7,16),
-
-36000 => RubyCoreSupport.rational_new!(-5,12),
-
-34200 => RubyCoreSupport.rational_new!(-19,48),
-
-32400 => RubyCoreSupport.rational_new!(-3,8),
-
-30600 => RubyCoreSupport.rational_new!(-17,48),
-
-28800 => RubyCoreSupport.rational_new!(-1,3),
-
-27000 => RubyCoreSupport.rational_new!(-5,16),
-
-25200 => RubyCoreSupport.rational_new!(-7,24),
-
-23400 => RubyCoreSupport.rational_new!(-13,48),
-
-21600 => RubyCoreSupport.rational_new!(-1,4),
-
-19800 => RubyCoreSupport.rational_new!(-11,48),
-
-18000 => RubyCoreSupport.rational_new!(-5,24),
-
-16200 => RubyCoreSupport.rational_new!(-3,16),
-
-14400 => RubyCoreSupport.rational_new!(-1,6),
-
-12600 => RubyCoreSupport.rational_new!(-7,48),
-
-10800 => RubyCoreSupport.rational_new!(-1,8),
-
-9000 => RubyCoreSupport.rational_new!(-5,48),
-
-7200 => RubyCoreSupport.rational_new!(-1,12),
-
-5400 => RubyCoreSupport.rational_new!(-1,16),
-
-3600 => RubyCoreSupport.rational_new!(-1,24),
-
-1800 => RubyCoreSupport.rational_new!(-1,48),
-
0 => RubyCoreSupport.rational_new!(0,1),
-
1800 => RubyCoreSupport.rational_new!(1,48),
-
3600 => RubyCoreSupport.rational_new!(1,24),
-
5400 => RubyCoreSupport.rational_new!(1,16),
-
7200 => RubyCoreSupport.rational_new!(1,12),
-
9000 => RubyCoreSupport.rational_new!(5,48),
-
10800 => RubyCoreSupport.rational_new!(1,8),
-
12600 => RubyCoreSupport.rational_new!(7,48),
-
14400 => RubyCoreSupport.rational_new!(1,6),
-
16200 => RubyCoreSupport.rational_new!(3,16),
-
18000 => RubyCoreSupport.rational_new!(5,24),
-
19800 => RubyCoreSupport.rational_new!(11,48),
-
21600 => RubyCoreSupport.rational_new!(1,4),
-
23400 => RubyCoreSupport.rational_new!(13,48),
-
25200 => RubyCoreSupport.rational_new!(7,24),
-
27000 => RubyCoreSupport.rational_new!(5,16),
-
28800 => RubyCoreSupport.rational_new!(1,3),
-
30600 => RubyCoreSupport.rational_new!(17,48),
-
32400 => RubyCoreSupport.rational_new!(3,8),
-
34200 => RubyCoreSupport.rational_new!(19,48),
-
36000 => RubyCoreSupport.rational_new!(5,12),
-
37800 => RubyCoreSupport.rational_new!(7,16),
-
39600 => RubyCoreSupport.rational_new!(11,24),
-
41400 => RubyCoreSupport.rational_new!(23,48),
-
43200 => RubyCoreSupport.rational_new!(1,2),
-
45000 => RubyCoreSupport.rational_new!(25,48),
-
46800 => RubyCoreSupport.rational_new!(13,24),
-
48600 => RubyCoreSupport.rational_new!(9,16),
-
50400 => RubyCoreSupport.rational_new!(7,12)}
-
-
# Returns a Rational expressing the fraction of a day that offset in
-
# seconds represents (i.e. equivalent to Rational(offset, 86400)).
-
1
def rational_for_offset(offset)
-
5
@@rational_cache[offset] || Rational(offset, 86400)
-
end
-
1
module_function :rational_for_offset
-
end
-
end
-
#--
-
# Copyright (c) 2008-2010 Philip Ross
-
#
-
# Permission is hereby granted, free of charge, to any person obtaining a copy
-
# of this software and associated documentation files (the "Software"), to deal
-
# in the Software without restriction, including without limitation the rights
-
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-
# copies of the Software, and to permit persons to whom the Software is
-
# furnished to do so, subject to the following conditions:
-
#
-
# The above copyright notice and this permission notice shall be included in all
-
# copies or substantial portions of the Software.
-
#
-
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
-
# THE SOFTWARE.
-
#++
-
-
1
require 'date'
-
1
require 'rational' unless defined?(Rational)
-
-
1
module TZInfo
-
-
# Methods to support different versions of Ruby.
-
1
module RubyCoreSupport #:nodoc:
-
-
# Use Rational.new! for performance reasons in Ruby 1.8.
-
# This has been removed from 1.9, but Rational performs better.
-
1
if Rational.respond_to? :new!
-
def self.rational_new!(numerator, denominator = 1)
-
Rational.new!(numerator, denominator)
-
end
-
else
-
1
def self.rational_new!(numerator, denominator = 1)
-
79
Rational(numerator, denominator)
-
end
-
end
-
-
# Ruby 1.8.6 introduced new! and deprecated new0.
-
# Ruby 1.9.0 removed new0.
-
# Ruby trunk revision 31668 removed the new! method.
-
# Still support new0 for better performance on older versions of Ruby (new0 indicates
-
# that the rational has already been reduced to its lowest terms).
-
# Fallback to jd with conversion from ajd if new! and new0 are unavailable.
-
1
if DateTime.respond_to? :new!
-
def self.datetime_new!(ajd = 0, of = 0, sg = Date::ITALY)
-
DateTime.new!(ajd, of, sg)
-
end
-
elsif DateTime.respond_to? :new0
-
def self.datetime_new!(ajd = 0, of = 0, sg = Date::ITALY)
-
DateTime.new0(ajd, of, sg)
-
end
-
else
-
1
HALF_DAYS_IN_DAY = rational_new!(1, 2)
-
-
1
def self.datetime_new!(ajd = 0, of = 0, sg = Date::ITALY)
-
# Convert from an Astronomical Julian Day number to a civil Julian Day number.
-
21
jd = ajd + of + HALF_DAYS_IN_DAY
-
-
# Ruby trunk revision 31862 changed the behaviour of DateTime.jd so that it will no
-
# longer accept a fractional civil Julian Day number if further arguments are specified.
-
# Calculate the hours, minutes and seconds to pass to jd.
-
-
21
jd_i = jd.to_i
-
21
jd_i -= 1 if jd < 0
-
21
hours = (jd - jd_i) * 24
-
21
hours_i = hours.to_i
-
21
minutes = (hours - hours_i) * 60
-
21
minutes_i = minutes.to_i
-
21
seconds = (minutes - minutes_i) * 60
-
-
21
DateTime.jd(jd_i, hours_i, minutes_i, seconds, of, sg)
-
end
-
end
-
end
-
end
-
#--
-
# Copyright (c) 2006-2010 Philip Ross
-
#
-
# Permission is hereby granted, free of charge, to any person obtaining a copy
-
# of this software and associated documentation files (the "Software"), to deal
-
# in the Software without restriction, including without limitation the rights
-
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-
# copies of the Software, and to permit persons to whom the Software is
-
# furnished to do so, subject to the following conditions:
-
#
-
# The above copyright notice and this permission notice shall be included in all
-
# copies or substantial portions of the Software.
-
#
-
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
-
# THE SOFTWARE.
-
#++
-
-
1
require 'date'
-
1
require 'time'
-
-
1
module TZInfo
-
# Used by TZInfo internally to represent either a Time, DateTime or integer
-
# timestamp (seconds since 1970-01-01 00:00:00).
-
1
class TimeOrDateTime #:nodoc:
-
1
include Comparable
-
-
# Constructs a new TimeOrDateTime. timeOrDateTime can be a Time, DateTime
-
# or an integer. If using a Time or DateTime, any time zone information is
-
# ignored.
-
1
def initialize(timeOrDateTime)
-
957
@time = nil
-
957
@datetime = nil
-
957
@timestamp = nil
-
-
957
if timeOrDateTime.is_a?(Time)
-
633
@time = timeOrDateTime
-
633
@time = Time.utc(@time.year, @time.mon, @time.mday, @time.hour, @time.min, @time.sec) unless @time.zone == 'UTC'
-
633
@orig = @time
-
324
elsif timeOrDateTime.is_a?(DateTime)
-
26
@datetime = timeOrDateTime
-
26
@datetime = @datetime.new_offset(0) unless @datetime.offset == 0
-
26
@orig = @datetime
-
else
-
298
@timestamp = timeOrDateTime.to_i
-
298
@orig = @timestamp
-
end
-
end
-
-
# Returns the time as a Time.
-
1
def to_time
-
1995
unless @time
-
272
if @timestamp
-
272
@time = Time.at(@timestamp).utc
-
else
-
@time = Time.utc(year, mon, mday, hour, min, sec)
-
end
-
end
-
-
1995
@time
-
end
-
-
# Returns the time as a DateTime.
-
1
def to_datetime
-
96
unless @datetime
-
48
@datetime = DateTime.new(year, mon, mday, hour, min, sec)
-
end
-
-
96
@datetime
-
end
-
-
# Returns the time as an integer timestamp.
-
1
def to_i
-
93
unless @timestamp
-
@timestamp = to_time.to_i
-
end
-
-
93
@timestamp
-
end
-
-
# Returns the time as the original time passed to new.
-
1
def to_orig
-
973
@orig
-
end
-
-
# Returns a string representation of the TimeOrDateTime.
-
1
def to_s
-
if @orig.is_a?(Time)
-
"Time: #{@orig.to_s}"
-
elsif @orig.is_a?(DateTime)
-
"DateTime: #{@orig.to_s}"
-
else
-
"Timestamp: #{@orig.to_s}"
-
end
-
end
-
-
# Returns internal object state as a programmer-readable string.
-
1
def inspect
-
"#<#{self.class}: #{@orig.inspect}>"
-
end
-
-
# Returns the year.
-
1
def year
-
394
if @time
-
394
@time.year
-
elsif @datetime
-
@datetime.year
-
else
-
to_time.year
-
end
-
end
-
-
# Returns the month of the year (1..12).
-
1
def mon
-
394
if @time
-
394
@time.mon
-
elsif @datetime
-
@datetime.mon
-
else
-
to_time.mon
-
end
-
end
-
1
alias :month :mon
-
-
# Returns the day of the month (1..n).
-
1
def mday
-
48
if @time
-
48
@time.mday
-
elsif @datetime
-
@datetime.mday
-
else
-
to_time.mday
-
end
-
end
-
1
alias :day :mday
-
-
# Returns the hour of the day (0..23).
-
1
def hour
-
48
if @time
-
48
@time.hour
-
elsif @datetime
-
@datetime.hour
-
else
-
to_time.hour
-
end
-
end
-
-
# Returns the minute of the hour (0..59).
-
1
def min
-
48
if @time
-
48
@time.min
-
elsif @datetime
-
@datetime.min
-
else
-
to_time.min
-
end
-
end
-
-
# Returns the second of the minute (0..60). (60 for a leap second).
-
1
def sec
-
48
if @time
-
48
@time.sec
-
elsif @datetime
-
@datetime.sec
-
else
-
to_time.sec
-
end
-
end
-
-
# Compares this TimeOrDateTime with another Time, DateTime, integer
-
# timestamp or TimeOrDateTime. Returns -1, 0 or +1 depending whether the
-
# receiver is less than, equal to, or greater than timeOrDateTime.
-
#
-
# Milliseconds and smaller units are ignored in the comparison.
-
1
def <=>(timeOrDateTime)
-
973
if timeOrDateTime.is_a?(TimeOrDateTime)
-
973
orig = timeOrDateTime.to_orig
-
-
973
if @orig.is_a?(DateTime) || orig.is_a?(DateTime)
-
# If either is a DateTime, assume it is there for a reason
-
# (i.e. for range).
-
48
to_datetime <=> timeOrDateTime.to_datetime
-
925
elsif orig.is_a?(Time)
-
925
to_time <=> timeOrDateTime.to_time
-
else
-
to_i <=> timeOrDateTime.to_i
-
end
-
elsif @orig.is_a?(DateTime) || timeOrDateTime.is_a?(DateTime)
-
# If either is a DateTime, assume it is there for a reason
-
# (i.e. for range).
-
to_datetime <=> TimeOrDateTime.wrap(timeOrDateTime).to_datetime
-
elsif timeOrDateTime.is_a?(Time)
-
to_time <=> timeOrDateTime
-
else
-
to_i <=> timeOrDateTime.to_i
-
end
-
end
-
-
# Adds a number of seconds to the TimeOrDateTime. Returns a new
-
# TimeOrDateTime, preserving what the original constructed type was.
-
# If the original type is a Time and the resulting calculation goes out of
-
# range for Times, then an exception will be raised by the Time class.
-
1
def +(seconds)
-
145
if seconds == 0
-
3
self
-
else
-
142
if @orig.is_a?(DateTime)
-
TimeOrDateTime.new(@orig + OffsetRationals.rational_for_offset(seconds))
-
else
-
# + defined for Time and integer timestamps
-
142
TimeOrDateTime.new(@orig + seconds)
-
end
-
end
-
end
-
-
# Subtracts a number of seconds from the TimeOrDateTime. Returns a new
-
# TimeOrDateTime, preserving what the original constructed type was.
-
# If the original type is a Time and the resulting calculation goes out of
-
# range for Times, then an exception will be raised by the Time class.
-
1
def -(seconds)
-
68
self + (-seconds)
-
end
-
-
# Similar to the + operator, but for cases where adding would cause a
-
# timestamp or time to go out of the allowed range, converts to a DateTime
-
# based TimeOrDateTime.
-
1
def add_with_convert(seconds)
-
103
if seconds == 0
-
5
self
-
else
-
98
if @orig.is_a?(DateTime)
-
5
TimeOrDateTime.new(@orig + OffsetRationals.rational_for_offset(seconds))
-
else
-
# A Time or timestamp.
-
93
result = to_i + seconds
-
-
93
if result < 0 || result > 2147483647
-
result = TimeOrDateTime.new(to_datetime + OffsetRationals.rational_for_offset(seconds))
-
else
-
93
result = TimeOrDateTime.new(@orig + seconds)
-
end
-
end
-
end
-
end
-
-
# Returns true if todt represents the same time and was originally
-
# constructed with the same type (DateTime, Time or timestamp) as this
-
# TimeOrDateTime.
-
1
def eql?(todt)
-
todt.respond_to?(:to_orig) && to_orig.eql?(todt.to_orig)
-
end
-
-
# Returns a hash of this TimeOrDateTime.
-
1
def hash
-
@orig.hash
-
end
-
-
# If no block is given, returns a TimeOrDateTime wrapping the given
-
# timeOrDateTime. If a block is specified, a TimeOrDateTime is constructed
-
# and passed to the block. The result of the block must be a TimeOrDateTime.
-
# to_orig will be called on the result and the result of to_orig will be
-
# returned.
-
#
-
# timeOrDateTime can be a Time, DateTime, integer timestamp or TimeOrDateTime.
-
# If a TimeOrDateTime is passed in, no new TimeOrDateTime will be constructed,
-
# the passed in value will be used.
-
1
def self.wrap(timeOrDateTime)
-
491
t = timeOrDateTime.is_a?(TimeOrDateTime) ? timeOrDateTime : TimeOrDateTime.new(timeOrDateTime)
-
-
491
if block_given?
-
145
t = yield t
-
-
145
if timeOrDateTime.is_a?(TimeOrDateTime)
-
t
-
145
elsif timeOrDateTime.is_a?(Time)
-
145
t.to_time
-
elsif timeOrDateTime.is_a?(DateTime)
-
t.to_datetime
-
else
-
t.to_i
-
end
-
else
-
346
t
-
end
-
end
-
end
-
end
-
#--
-
# Copyright (c) 2005-2010 Philip Ross
-
#
-
# Permission is hereby granted, free of charge, to any person obtaining a copy
-
# of this software and associated documentation files (the "Software"), to deal
-
# in the Software without restriction, including without limitation the rights
-
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-
# copies of the Software, and to permit persons to whom the Software is
-
# furnished to do so, subject to the following conditions:
-
#
-
# The above copyright notice and this permission notice shall be included in all
-
# copies or substantial portions of the Software.
-
#
-
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
-
# THE SOFTWARE.
-
#++
-
-
1
require 'date'
-
-
1
module TZInfo
-
# Indicate a specified time in a local timezone has more than one
-
# possible time in UTC. This happens when switching from daylight savings time
-
# to normal time where the clocks are rolled back. Thrown by period_for_local
-
# and local_to_utc when using an ambiguous time and not specifying any
-
# means to resolve the ambiguity.
-
1
class AmbiguousTime < StandardError
-
end
-
-
# Thrown to indicate that no TimezonePeriod matching a given time could be found.
-
1
class PeriodNotFound < StandardError
-
end
-
-
# Thrown by Timezone#get if the identifier given is not valid.
-
1
class InvalidTimezoneIdentifier < StandardError
-
end
-
-
# Thrown if an attempt is made to use a timezone created with Timezone.new(nil).
-
1
class UnknownTimezone < StandardError
-
end
-
-
# Timezone is the base class of all timezones. It provides a factory method
-
# get to access timezones by identifier. Once a specific Timezone has been
-
# retrieved, DateTimes, Times and timestamps can be converted between the UTC
-
# and the local time for the zone. For example:
-
#
-
# tz = TZInfo::Timezone.get('America/New_York')
-
# puts tz.utc_to_local(DateTime.new(2005,8,29,15,35,0)).to_s
-
# puts tz.local_to_utc(Time.utc(2005,8,29,11,35,0)).to_s
-
# puts tz.utc_to_local(1125315300).to_s
-
#
-
# Each time conversion method returns an object of the same type it was
-
# passed.
-
#
-
# The timezone information all comes from the tz database
-
# (see http://www.twinsun.com/tz/tz-link.htm)
-
1
class Timezone
-
1
include Comparable
-
-
# Cache of loaded zones by identifier to avoid using require if a zone
-
# has already been loaded.
-
1
@@loaded_zones = {}
-
-
# Whether the timezones index has been loaded yet.
-
1
@@index_loaded = false
-
-
# Default value of the dst parameter of the local_to_utc and
-
# period_for_local methods.
-
1
@@default_dst = nil
-
-
# Sets the default value of the optional dst parameter of the
-
# local_to_utc and period_for_local methods. Can be set to nil, true or
-
# false.
-
#
-
# The value of default_dst defaults to nil if unset.
-
1
def self.default_dst=(value)
-
@@default_dst = value.nil? ? nil : !!value
-
end
-
-
# Gets the default value of the optional dst parameter of the
-
# local_to_utc and period_for_local methods. Can be set to nil, true or
-
# false.
-
1
def self.default_dst
-
@@default_dst
-
end
-
-
# Returns a timezone by its identifier (e.g. "Europe/London",
-
# "America/Chicago" or "UTC").
-
#
-
# Raises InvalidTimezoneIdentifier if the timezone couldn't be found.
-
1
def self.get(identifier)
-
151
instance = @@loaded_zones[identifier]
-
151
unless instance
-
127
raise InvalidTimezoneIdentifier, 'Invalid identifier' if identifier !~ /^[A-Za-z0-9\+\-_]+(\/[A-Za-z0-9\+\-_]+)*$/
-
127
identifier = identifier.gsub(/-/, '__m__').gsub(/\+/, '__p__')
-
127
begin
-
# Use a temporary variable to avoid an rdoc warning
-
127
file = "tzinfo/definitions/#{identifier}".untaint
-
127
require file
-
-
127
m = Definitions
-
127
identifier.split(/\//).each {|part|
-
255
m = m.const_get(part)
-
}
-
-
127
info = m.get
-
-
# Could make Timezone subclasses register an interest in an info
-
# type. Since there are currently only two however, there isn't
-
# much point.
-
127
if info.kind_of?(DataTimezoneInfo)
-
122
instance = DataTimezone.new(info)
-
elsif info.kind_of?(LinkedTimezoneInfo)
-
5
instance = LinkedTimezone.new(info)
-
else
-
raise InvalidTimezoneIdentifier, "No handler for info type #{info.class}"
-
end
-
-
127
@@loaded_zones[instance.identifier] = instance
-
rescue LoadError, NameError => e
-
raise InvalidTimezoneIdentifier, e.message
-
end
-
end
-
-
151
instance
-
end
-
-
# Returns a proxy for the Timezone with the given identifier. The proxy
-
# will cause the real timezone to be loaded when an attempt is made to
-
# find a period or convert a time. get_proxy will not validate the
-
# identifier. If an invalid identifier is specified, no exception will be
-
# raised until the proxy is used.
-
1
def self.get_proxy(identifier)
-
TimezoneProxy.new(identifier)
-
end
-
-
# If identifier is nil calls super(), otherwise calls get. An identfier
-
# should always be passed in when called externally.
-
1
def self.new(identifier = nil)
-
275
if identifier
-
get(identifier)
-
else
-
275
super()
-
end
-
end
-
-
# Returns an array containing all the available Timezones.
-
#
-
# Returns TimezoneProxy objects to avoid the overhead of loading Timezone
-
# definitions until a conversion is actually required.
-
1
def self.all
-
get_proxies(all_identifiers)
-
end
-
-
# Returns an array containing the identifiers of all the available
-
# Timezones.
-
1
def self.all_identifiers
-
load_index
-
Indexes::Timezones.timezones
-
end
-
-
# Returns an array containing all the available Timezones that are based
-
# on data (are not links to other Timezones).
-
#
-
# Returns TimezoneProxy objects to avoid the overhead of loading Timezone
-
# definitions until a conversion is actually required.
-
1
def self.all_data_zones
-
get_proxies(all_data_zone_identifiers)
-
end
-
-
# Returns an array containing the identifiers of all the available
-
# Timezones that are based on data (are not links to other Timezones)..
-
1
def self.all_data_zone_identifiers
-
load_index
-
Indexes::Timezones.data_timezones
-
end
-
-
# Returns an array containing all the available Timezones that are links
-
# to other Timezones.
-
#
-
# Returns TimezoneProxy objects to avoid the overhead of loading Timezone
-
# definitions until a conversion is actually required.
-
1
def self.all_linked_zones
-
get_proxies(all_linked_zone_identifiers)
-
end
-
-
# Returns an array containing the identifiers of all the available
-
# Timezones that are links to other Timezones.
-
1
def self.all_linked_zone_identifiers
-
load_index
-
Indexes::Timezones.linked_timezones
-
end
-
-
# Returns all the Timezones defined for all Countries. This is not the
-
# complete set of Timezones as some are not country specific (e.g.
-
# 'Etc/GMT').
-
#
-
# Returns TimezoneProxy objects to avoid the overhead of loading Timezone
-
# definitions until a conversion is actually required.
-
1
def self.all_country_zones
-
Country.all_codes.inject([]) {|zones,country|
-
zones += Country.get(country).zones
-
}
-
end
-
-
# Returns all the zone identifiers defined for all Countries. This is not the
-
# complete set of zone identifiers as some are not country specific (e.g.
-
# 'Etc/GMT'). You can obtain a Timezone instance for a given identifier
-
# with the get method.
-
1
def self.all_country_zone_identifiers
-
Country.all_codes.inject([]) {|zones,country|
-
zones += Country.get(country).zone_identifiers
-
}
-
end
-
-
# Returns all US Timezone instances. A shortcut for
-
# TZInfo::Country.get('US').zones.
-
#
-
# Returns TimezoneProxy objects to avoid the overhead of loading Timezone
-
# definitions until a conversion is actually required.
-
1
def self.us_zones
-
Country.get('US').zones
-
end
-
-
# Returns all US zone identifiers. A shortcut for
-
# TZInfo::Country.get('US').zone_identifiers.
-
1
def self.us_zone_identifiers
-
Country.get('US').zone_identifiers
-
end
-
-
# The identifier of the timezone, e.g. "Europe/Paris".
-
1
def identifier
-
raise UnknownTimezone, 'TZInfo::Timezone constructed directly'
-
end
-
-
# An alias for identifier.
-
1
def name
-
# Don't use alias, as identifier gets overridden.
-
1
identifier
-
end
-
-
# Returns a friendlier version of the identifier.
-
1
def to_s
-
friendly_identifier
-
end
-
-
# Returns internal object state as a programmer-readable string.
-
1
def inspect
-
"#<#{self.class}: #{identifier}>"
-
end
-
-
# Returns a friendlier version of the identifier. Set skip_first_part to
-
# omit the first part of the identifier (typically a region name) where
-
# there is more than one part.
-
#
-
# For example:
-
#
-
# Timezone.get('Europe/Paris').friendly_identifier(false) #=> "Europe - Paris"
-
# Timezone.get('Europe/Paris').friendly_identifier(true) #=> "Paris"
-
# Timezone.get('America/Indiana/Knox').friendly_identifier(false) #=> "America - Knox, Indiana"
-
# Timezone.get('America/Indiana/Knox').friendly_identifier(true) #=> "Knox, Indiana"
-
1
def friendly_identifier(skip_first_part = false)
-
parts = identifier.split('/')
-
if parts.empty?
-
# shouldn't happen
-
identifier
-
elsif parts.length == 1
-
parts[0]
-
else
-
if skip_first_part
-
result = ''
-
else
-
result = parts[0] + ' - '
-
end
-
-
parts[1, parts.length - 1].reverse_each {|part|
-
part.gsub!(/_/, ' ')
-
-
if part.index(/[a-z]/)
-
# Missing a space if a lower case followed by an upper case and the
-
# name isn't McXxxx.
-
part.gsub!(/([^M][a-z])([A-Z])/, '\1 \2')
-
part.gsub!(/([M][a-bd-z])([A-Z])/, '\1 \2')
-
-
# Missing an apostrophe if two consecutive upper case characters.
-
part.gsub!(/([A-Z])([A-Z])/, '\1\'\2')
-
end
-
-
result << part
-
result << ', '
-
}
-
-
result.slice!(result.length - 2, 2)
-
result
-
end
-
end
-
-
# Returns the TimezonePeriod for the given UTC time. utc can either be
-
# a DateTime, Time or integer timestamp (Time.to_i). Any timezone
-
# information in utc is ignored (it is treated as a UTC time).
-
1
def period_for_utc(utc)
-
raise UnknownTimezone, 'TZInfo::Timezone constructed directly'
-
end
-
-
# Returns the set of TimezonePeriod instances that are valid for the given
-
# local time as an array. If you just want a single period, use
-
# period_for_local instead and specify how ambiguities should be resolved.
-
# Returns an empty array if no periods are found for the given time.
-
1
def periods_for_local(local)
-
raise UnknownTimezone, 'TZInfo::Timezone constructed directly'
-
end
-
-
# Returns the TimezonePeriod for the given local time. local can either be
-
# a DateTime, Time or integer timestamp (Time.to_i). Any timezone
-
# information in local is ignored (it is treated as a time in the current
-
# timezone).
-
#
-
# Warning: There are local times that have no equivalent UTC times (e.g.
-
# in the transition from standard time to daylight savings time). There are
-
# also local times that have more than one UTC equivalent (e.g. in the
-
# transition from daylight savings time to standard time).
-
#
-
# In the first case (no equivalent UTC time), a PeriodNotFound exception
-
# will be raised.
-
#
-
# In the second case (more than one equivalent UTC time), an AmbiguousTime
-
# exception will be raised unless the optional dst parameter or block
-
# handles the ambiguity.
-
#
-
# If the ambiguity is due to a transition from daylight savings time to
-
# standard time, the dst parameter can be used to select whether the
-
# daylight savings time or local time is used. For example,
-
#
-
# Timezone.get('America/New_York').period_for_local(DateTime.new(2004,10,31,1,30,0))
-
#
-
# would raise an AmbiguousTime exception.
-
#
-
# Specifying dst=true would the daylight savings period from April to
-
# October 2004. Specifying dst=false would return the standard period
-
# from October 2004 to April 2005.
-
#
-
# If the dst parameter does not resolve the ambiguity, and a block is
-
# specified, it is called. The block must take a single parameter - an
-
# array of the periods that need to be resolved. The block can select and
-
# return a single period or return nil or an empty array
-
# to cause an AmbiguousTime exception to be raised.
-
#
-
# The default value of the dst parameter can be specified by setting
-
# Timezone.default_dst. If default_dst is not set, or is set to nil, then
-
# an AmbiguousTime exception will be raised in ambiguous situations unless
-
# a block is given to resolve the ambiguity.
-
1
def period_for_local(local, dst = Timezone.default_dst)
-
126
results = periods_for_local(local)
-
-
126
if results.empty?
-
raise PeriodNotFound
-
126
elsif results.size < 2
-
126
results.first
-
else
-
# ambiguous result try to resolve
-
-
if !dst.nil?
-
matches = results.find_all {|period| period.dst? == dst}
-
results = matches if !matches.empty?
-
end
-
-
if results.size < 2
-
results.first
-
else
-
# still ambiguous, try the block
-
-
if block_given?
-
results = yield results
-
end
-
-
if results.is_a?(TimezonePeriod)
-
results
-
elsif results && results.size == 1
-
results.first
-
else
-
raise AmbiguousTime, "#{local} is an ambiguous local time."
-
end
-
end
-
end
-
end
-
-
# Converts a time in UTC to the local timezone. utc can either be
-
# a DateTime, Time or timestamp (Time.to_i). The returned time has the same
-
# type as utc. Any timezone information in utc is ignored (it is treated as
-
# a UTC time).
-
1
def utc_to_local(utc)
-
TimeOrDateTime.wrap(utc) {|wrapped|
-
period_for_utc(wrapped).to_local(wrapped)
-
}
-
end
-
-
# Converts a time in the local timezone to UTC. local can either be
-
# a DateTime, Time or timestamp (Time.to_i). The returned time has the same
-
# type as local. Any timezone information in local is ignored (it is treated
-
# as a local time).
-
#
-
# Warning: There are local times that have no equivalent UTC times (e.g.
-
# in the transition from standard time to daylight savings time). There are
-
# also local times that have more than one UTC equivalent (e.g. in the
-
# transition from daylight savings time to standard time).
-
#
-
# In the first case (no equivalent UTC time), a PeriodNotFound exception
-
# will be raised.
-
#
-
# In the second case (more than one equivalent UTC time), an AmbiguousTime
-
# exception will be raised unless the optional dst parameter or block
-
# handles the ambiguity.
-
#
-
# If the ambiguity is due to a transition from daylight savings time to
-
# standard time, the dst parameter can be used to select whether the
-
# daylight savings time or local time is used. For example,
-
#
-
# Timezone.get('America/New_York').local_to_utc(DateTime.new(2004,10,31,1,30,0))
-
#
-
# would raise an AmbiguousTime exception.
-
#
-
# Specifying dst=true would return 2004-10-31 5:30:00. Specifying dst=false
-
# would return 2004-10-31 6:30:00.
-
#
-
# If the dst parameter does not resolve the ambiguity, and a block is
-
# specified, it is called. The block must take a single parameter - an
-
# array of the periods that need to be resolved. The block can return a
-
# single period to use to convert the time or return nil or an empty array
-
# to cause an AmbiguousTime exception to be raised.
-
#
-
# The default value of the dst parameter can be specified by setting
-
# Timezone.default_dst. If default_dst is not set, or is set to nil, then
-
# an AmbiguousTime exception will be raised in ambiguous situations unless
-
# a block is given to resolve the ambiguity.
-
1
def local_to_utc(local, dst = Timezone.default_dst)
-
TimeOrDateTime.wrap(local) {|wrapped|
-
if block_given?
-
period = period_for_local(wrapped, dst) {|periods| yield periods }
-
else
-
period = period_for_local(wrapped, dst)
-
end
-
-
period.to_utc(wrapped)
-
}
-
end
-
-
# Returns the current time in the timezone as a Time.
-
1
def now
-
utc_to_local(Time.now.utc)
-
end
-
-
# Returns the TimezonePeriod for the current time.
-
1
def current_period
-
145
period_for_utc(Time.now.utc)
-
end
-
-
# Returns the current Time and TimezonePeriod as an array. The first element
-
# is the time, the second element is the period.
-
1
def current_period_and_time
-
utc = Time.now.utc
-
period = period_for_utc(utc)
-
[period.to_local(utc), period]
-
end
-
-
1
alias :current_time_and_period :current_period_and_time
-
-
# Converts a time in UTC to local time and returns it as a string
-
# according to the given format. The formatting is identical to
-
# Time.strftime and DateTime.strftime, except %Z is replaced with the
-
# timezone abbreviation for the specified time (for example, EST or EDT).
-
1
def strftime(format, utc = Time.now.utc)
-
period = period_for_utc(utc)
-
local = period.to_local(utc)
-
local = Time.at(local).utc unless local.kind_of?(Time) || local.kind_of?(DateTime)
-
abbreviation = period.abbreviation.to_s.gsub(/%/, '%%')
-
-
format = format.gsub(/(.?)%Z/) do
-
if $1 == '%'
-
# return %%Z so the real strftime treats it as a literal %Z too
-
'%%Z'
-
else
-
"#$1#{abbreviation}"
-
end
-
end
-
-
local.strftime(format)
-
end
-
-
# Compares two Timezones based on their identifier. Returns -1 if tz is less
-
# than self, 0 if tz is equal to self and +1 if tz is greater than self.
-
1
def <=>(tz)
-
identifier <=> tz.identifier
-
end
-
-
# Returns true if and only if the identifier of tz is equal to the
-
# identifier of this Timezone.
-
1
def eql?(tz)
-
self == tz
-
end
-
-
# Returns a hash of this Timezone.
-
1
def hash
-
identifier.hash
-
end
-
-
# Dumps this Timezone for marshalling.
-
1
def _dump(limit)
-
identifier
-
end
-
-
# Loads a marshalled Timezone.
-
1
def self._load(data)
-
Timezone.get(data)
-
end
-
-
1
private
-
# Loads in the index of timezones if it hasn't already been loaded.
-
1
def self.load_index
-
unless @@index_loaded
-
require 'tzinfo/indexes/timezones'
-
@@index_loaded = true
-
end
-
end
-
-
# Returns an array of proxies corresponding to the given array of
-
# identifiers.
-
1
def self.get_proxies(identifiers)
-
identifiers.collect {|identifier| get_proxy(identifier)}
-
end
-
end
-
end
-
#--
-
# Copyright (c) 2006-2010 Philip Ross
-
#
-
# Permission is hereby granted, free of charge, to any person obtaining a copy
-
# of this software and associated documentation files (the "Software"), to deal
-
# in the Software without restriction, including without limitation the rights
-
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-
# copies of the Software, and to permit persons to whom the Software is
-
# furnished to do so, subject to the following conditions:
-
#
-
# The above copyright notice and this permission notice shall be included in all
-
# copies or substantial portions of the Software.
-
#
-
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
-
# THE SOFTWARE.
-
#++
-
-
1
module TZInfo
-
-
# TimezoneDefinition is included into Timezone definition modules.
-
# TimezoneDefinition provides the methods for defining timezones.
-
1
module TimezoneDefinition #:nodoc:
-
# Add class methods to the includee.
-
1
def self.append_features(base)
-
127
super
-
127
base.extend(ClassMethods)
-
end
-
-
# Class methods for inclusion.
-
1
module ClassMethods #:nodoc:
-
# Returns and yields a DataTimezoneInfo object to define a timezone.
-
1
def timezone(identifier)
-
122
yield @timezone = DataTimezoneInfo.new(identifier)
-
end
-
-
# Defines a linked timezone.
-
1
def linked_timezone(identifier, link_to_identifier)
-
5
@timezone = LinkedTimezoneInfo.new(identifier, link_to_identifier)
-
end
-
-
# Returns the last TimezoneInfo to be defined with timezone or
-
# linked_timezone.
-
1
def get
-
127
@timezone
-
end
-
end
-
end
-
end
-
#--
-
# Copyright (c) 2006 Philip Ross
-
#
-
# Permission is hereby granted, free of charge, to any person obtaining a copy
-
# of this software and associated documentation files (the "Software"), to deal
-
# in the Software without restriction, including without limitation the rights
-
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-
# copies of the Software, and to permit persons to whom the Software is
-
# furnished to do so, subject to the following conditions:
-
#
-
# The above copyright notice and this permission notice shall be included in all
-
# copies or substantial portions of the Software.
-
#
-
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
-
# THE SOFTWARE.
-
#++
-
-
1
module TZInfo
-
# The timezone index file includes TimezoneIndexDefinition which provides
-
# methods used to define timezones in the index.
-
1
module TimezoneIndexDefinition #:nodoc:
-
1
def self.append_features(base)
-
super
-
base.extend(ClassMethods)
-
base.instance_eval do
-
@timezones = []
-
@data_timezones = []
-
@linked_timezones = []
-
end
-
end
-
-
1
module ClassMethods #:nodoc:
-
# Defines a timezone based on data.
-
1
def timezone(identifier)
-
@timezones << identifier
-
@data_timezones << identifier
-
end
-
-
# Defines a timezone which is a link to another timezone.
-
1
def linked_timezone(identifier)
-
@timezones << identifier
-
@linked_timezones << identifier
-
end
-
-
# Returns a frozen array containing the identifiers of all the timezones.
-
# Identifiers appear in the order they were defined in the index.
-
1
def timezones
-
@timezones.freeze
-
end
-
-
# Returns a frozen array containing the identifiers of all data timezones.
-
# Identifiers appear in the order they were defined in the index.
-
1
def data_timezones
-
@data_timezones.freeze
-
end
-
-
# Returns a frozen array containing the identifiers of all linked
-
# timezones. Identifiers appear in the order they were defined in
-
# the index.
-
1
def linked_timezones
-
@linked_timezones.freeze
-
end
-
end
-
end
-
end
-
#--
-
# Copyright (c) 2006 Philip Ross
-
#
-
# Permission is hereby granted, free of charge, to any person obtaining a copy
-
# of this software and associated documentation files (the "Software"), to deal
-
# in the Software without restriction, including without limitation the rights
-
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-
# copies of the Software, and to permit persons to whom the Software is
-
# furnished to do so, subject to the following conditions:
-
#
-
# The above copyright notice and this permission notice shall be included in all
-
# copies or substantial portions of the Software.
-
#
-
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
-
# THE SOFTWARE.
-
#++
-
-
1
module TZInfo
-
# Represents a timezone defined in a data module.
-
1
class TimezoneInfo #:nodoc:
-
-
# The timezone identifier.
-
1
attr_reader :identifier
-
-
# Constructs a new TimezoneInfo with an identifier.
-
1
def initialize(identifier)
-
127
@identifier = identifier
-
end
-
-
# Returns internal object state as a programmer-readable string.
-
1
def inspect
-
"#<#{self.class}: #@identifier>"
-
end
-
end
-
end
-
#--
-
# Copyright (c) 2006 Philip Ross
-
#
-
# Permission is hereby granted, free of charge, to any person obtaining a copy
-
# of this software and associated documentation files (the "Software"), to deal
-
# in the Software without restriction, including without limitation the rights
-
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-
# copies of the Software, and to permit persons to whom the Software is
-
# furnished to do so, subject to the following conditions:
-
#
-
# The above copyright notice and this permission notice shall be included in all
-
# copies or substantial portions of the Software.
-
#
-
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
-
# THE SOFTWARE.
-
#++
-
-
1
module TZInfo
-
# Represents an offset defined in a Timezone data file.
-
1
class TimezoneOffsetInfo #:nodoc:
-
# The base offset of the timezone from UTC in seconds.
-
1
attr_reader :utc_offset
-
-
# The offset from standard time for the zone in seconds (i.e. non-zero if
-
# daylight savings is being observed).
-
1
attr_reader :std_offset
-
-
# The total offset of this observance from UTC in seconds
-
# (utc_offset + std_offset).
-
1
attr_reader :utc_total_offset
-
-
# The abbreviation that identifies this observance, e.g. "GMT"
-
# (Greenwich Mean Time) or "BST" (British Summer Time) for "Europe/London". The returned identifier is a
-
# symbol.
-
1
attr_reader :abbreviation
-
-
# Constructs a new TimezoneOffsetInfo. utc_offset and std_offset are
-
# specified in seconds.
-
1
def initialize(utc_offset, std_offset, abbreviation)
-
610
@utc_offset = utc_offset
-
610
@std_offset = std_offset
-
610
@abbreviation = abbreviation
-
-
610
@utc_total_offset = @utc_offset + @std_offset
-
end
-
-
# True if std_offset is non-zero.
-
1
def dst?
-
2
@std_offset != 0
-
end
-
-
# Converts a UTC DateTime to local time based on the offset of this period.
-
1
def to_local(utc)
-
77
TimeOrDateTime.wrap(utc) {|wrapped|
-
77
wrapped + @utc_total_offset
-
}
-
end
-
-
# Converts a local DateTime to UTC based on the offset of this period.
-
1
def to_utc(local)
-
68
TimeOrDateTime.wrap(local) {|wrapped|
-
68
wrapped - @utc_total_offset
-
}
-
end
-
-
# Returns true if and only if toi has the same utc_offset, std_offset
-
# and abbreviation as this TimezoneOffsetInfo.
-
1
def ==(toi)
-
toi.respond_to?(:utc_offset) && toi.respond_to?(:std_offset) && toi.respond_to?(:abbreviation) &&
-
utc_offset == toi.utc_offset && std_offset == toi.std_offset && abbreviation == toi.abbreviation
-
end
-
-
# Returns true if and only if toi has the same utc_offset, std_offset
-
# and abbreviation as this TimezoneOffsetInfo.
-
1
def eql?(toi)
-
self == toi
-
end
-
-
# Returns a hash of this TimezoneOffsetInfo.
-
1
def hash
-
utc_offset.hash ^ std_offset.hash ^ abbreviation.hash
-
end
-
-
# Returns internal object state as a programmer-readable string.
-
1
def inspect
-
"#<#{self.class}: #@utc_offset,#@std_offset,#@abbreviation>"
-
end
-
end
-
end
-
#--
-
# Copyright (c) 2005-2010 Philip Ross
-
#
-
# Permission is hereby granted, free of charge, to any person obtaining a copy
-
# of this software and associated documentation files (the "Software"), to deal
-
# in the Software without restriction, including without limitation the rights
-
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-
# copies of the Software, and to permit persons to whom the Software is
-
# furnished to do so, subject to the following conditions:
-
#
-
# The above copyright notice and this permission notice shall be included in all
-
# copies or substantial portions of the Software.
-
#
-
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
-
# THE SOFTWARE.
-
#++
-
-
1
module TZInfo
-
# A period of time in a timezone where the same offset from UTC applies.
-
#
-
# All the methods that take times accept instances of Time, DateTime or
-
# integer timestamps.
-
1
class TimezonePeriod
-
# The TimezoneTransitionInfo that defines the start of this TimezonePeriod
-
# (may be nil if unbounded).
-
1
attr_reader :start_transition
-
-
# The TimezoneTransitionInfo that defines the end of this TimezonePeriod
-
# (may be nil if unbounded).
-
1
attr_reader :end_transition
-
-
# The TimezoneOffsetInfo for this period.
-
1
attr_reader :offset
-
-
# Initializes a new TimezonePeriod.
-
1
def initialize(start_transition, end_transition, offset = nil)
-
348
@start_transition = start_transition
-
348
@end_transition = end_transition
-
-
348
if offset
-
2
raise ArgumentError, 'Offset specified with transitions' if @start_transition || @end_transition
-
2
@offset = offset
-
else
-
346
if @start_transition
-
346
@offset = @start_transition.offset
-
elsif @end_transition
-
@offset = @end_transition.previous_offset
-
else
-
raise ArgumentError, 'No offset specified and no transitions to determine it from'
-
end
-
end
-
-
348
@utc_total_offset_rational = nil
-
end
-
-
# Base offset of the timezone from UTC (seconds).
-
1
def utc_offset
-
6289
@offset.utc_offset
-
end
-
-
# Offset from the local time where daylight savings is in effect (seconds).
-
# E.g.: utc_offset could be -5 hours. Normally, std_offset would be 0.
-
# During daylight savings, std_offset would typically become +1 hours.
-
1
def std_offset
-
@offset.std_offset
-
end
-
-
# The identifier of this period, e.g. "GMT" (Greenwich Mean Time) or "BST"
-
# (British Summer Time) for "Europe/London". The returned identifier is a
-
# symbol.
-
1
def abbreviation
-
20
@offset.abbreviation
-
end
-
1
alias :zone_identifier :abbreviation
-
-
# Total offset from UTC (seconds). Equal to utc_offset + std_offset.
-
1
def utc_total_offset
-
47
@offset.utc_total_offset
-
end
-
-
# Total offset from UTC (days). Result is a Rational.
-
1
def utc_total_offset_rational
-
unless @utc_total_offset_rational
-
@utc_total_offset_rational = OffsetRationals.rational_for_offset(utc_total_offset)
-
end
-
@utc_total_offset_rational
-
end
-
-
# The start time of the period in UTC as a DateTime. May be nil if unbounded.
-
1
def utc_start
-
@start_transition ? @start_transition.at.to_datetime : nil
-
end
-
-
# The end time of the period in UTC as a DateTime. May be nil if unbounded.
-
1
def utc_end
-
@end_transition ? @end_transition.at.to_datetime : nil
-
end
-
-
# The start time of the period in local time as a DateTime. May be nil if
-
# unbounded.
-
1
def local_start
-
@start_transition ? @start_transition.local_start.to_datetime : nil
-
end
-
-
# The end time of the period in local time as a DateTime. May be nil if
-
# unbounded.
-
1
def local_end
-
@end_transition ? @end_transition.local_end.to_datetime : nil
-
end
-
-
# true if daylight savings is in effect for this period; otherwise false.
-
1
def dst?
-
2
@offset.dst?
-
end
-
-
# true if this period is valid for the given UTC DateTime; otherwise false.
-
1
def valid_for_utc?(utc)
-
utc_after_start?(utc) && utc_before_end?(utc)
-
end
-
-
# true if the given UTC DateTime is after the start of the period
-
# (inclusive); otherwise false.
-
1
def utc_after_start?(utc)
-
!@start_transition || @start_transition.at <= utc
-
end
-
-
# true if the given UTC DateTime is before the end of the period
-
# (exclusive); otherwise false.
-
1
def utc_before_end?(utc)
-
!@end_transition || @end_transition.at > utc
-
end
-
-
# true if this period is valid for the given local DateTime; otherwise false.
-
1
def valid_for_local?(local)
-
local_after_start?(local) && local_before_end?(local)
-
end
-
-
# true if the given local DateTime is after the start of the period
-
# (inclusive); otherwise false.
-
1
def local_after_start?(local)
-
!@start_transition || @start_transition.local_start <= local
-
end
-
-
# true if the given local DateTime is before the end of the period
-
# (exclusive); otherwise false.
-
1
def local_before_end?(local)
-
!@end_transition || @end_transition.local_end > local
-
end
-
-
# Converts a UTC DateTime to local time based on the offset of this period.
-
1
def to_local(utc)
-
77
@offset.to_local(utc)
-
end
-
-
# Converts a local DateTime to UTC based on the offset of this period.
-
1
def to_utc(local)
-
68
@offset.to_utc(local)
-
end
-
-
# Returns true if this TimezonePeriod is equal to p. This compares the
-
# start_transition, end_transition and offset using ==.
-
1
def ==(p)
-
p.respond_to?(:start_transition) && p.respond_to?(:end_transition) &&
-
p.respond_to?(:offset) && start_transition == p.start_transition &&
-
end_transition == p.end_transition && offset == p.offset
-
end
-
-
# Returns true if this TimezonePeriods is equal to p. This compares the
-
# start_transition, end_transition and offset using eql?
-
1
def eql?(p)
-
p.respond_to?(:start_transition) && p.respond_to?(:end_transition) &&
-
p.respond_to?(:offset) && start_transition.eql?(p.start_transition) &&
-
end_transition.eql?(p.end_transition) && offset.eql?(p.offset)
-
end
-
-
# Returns a hash of this TimezonePeriod.
-
1
def hash
-
result = @start_transition.hash ^ @end_transition.hash
-
result ^= @offset.hash unless @start_transition || @end_transition
-
result
-
end
-
-
# Returns internal object state as a programmer-readable string.
-
1
def inspect
-
result = "#<#{self.class}: #{@start_transition.inspect},#{@end_transition.inspect}"
-
result << ",#{@offset.inspect}>" unless @start_transition || @end_transition
-
result + '>'
-
end
-
end
-
end
-
#--
-
# Copyright (c) 2005-2010 Philip Ross
-
#
-
# Permission is hereby granted, free of charge, to any person obtaining a copy
-
# of this software and associated documentation files (the "Software"), to deal
-
# in the Software without restriction, including without limitation the rights
-
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-
# copies of the Software, and to permit persons to whom the Software is
-
# furnished to do so, subject to the following conditions:
-
#
-
# The above copyright notice and this permission notice shall be included in all
-
# copies or substantial portions of the Software.
-
#
-
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
-
# THE SOFTWARE.
-
#++
-
-
1
module TZInfo
-
-
# A proxy class representing a timezone with a given identifier. TimezoneProxy
-
# inherits from Timezone and can be treated like any Timezone loaded with
-
# Timezone.get.
-
#
-
# The first time an attempt is made to access the data for the timezone, the
-
# real Timezone is loaded. If the proxy's identifier was not valid, then an
-
# exception will be raised at this point.
-
1
class TimezoneProxy < Timezone
-
# Construct a new TimezoneProxy for the given identifier. The identifier
-
# is not checked when constructing the proxy. It will be validated on the
-
# when the real Timezone is loaded.
-
1
def self.new(identifier)
-
# Need to override new to undo the behaviour introduced in Timezone#new.
-
148
tzp = super()
-
148
tzp.send(:setup, identifier)
-
148
tzp
-
end
-
-
# The identifier of the timezone, e.g. "Europe/Paris".
-
1
def identifier
-
1
@real_timezone ? @real_timezone.identifier : @identifier
-
end
-
-
# Returns the TimezonePeriod for the given UTC time. utc can either be
-
# a DateTime, Time or integer timestamp (Time.to_i). Any timezone
-
# information in utc is ignored (it is treated as a UTC time).
-
1
def period_for_utc(utc)
-
222
real_timezone.period_for_utc(utc)
-
end
-
-
# Returns the set of TimezonePeriod instances that are valid for the given
-
# local time as an array. If you just want a single period, use
-
# period_for_local instead and specify how abiguities should be resolved.
-
# Returns an empty array if no periods are found for the given time.
-
1
def periods_for_local(local)
-
126
real_timezone.periods_for_local(local)
-
end
-
-
# Dumps this TimezoneProxy for marshalling.
-
1
def _dump(limit)
-
identifier
-
end
-
-
# Loads a marshalled TimezoneProxy.
-
1
def self._load(data)
-
TimezoneProxy.new(data)
-
end
-
-
1
private
-
1
def setup(identifier)
-
148
@identifier = identifier
-
148
@real_timezone = nil
-
end
-
-
1
def real_timezone
-
348
@real_timezone ||= Timezone.get(@identifier)
-
end
-
end
-
end
-
#--
-
# Copyright (c) 2006-2010 Philip Ross
-
#
-
# Permission is hereby granted, free of charge, to any person obtaining a copy
-
# of this software and associated documentation files (the "Software"), to deal
-
# in the Software without restriction, including without limitation the rights
-
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-
# copies of the Software, and to permit persons to whom the Software is
-
# furnished to do so, subject to the following conditions:
-
#
-
# The above copyright notice and this permission notice shall be included in all
-
# copies or substantial portions of the Software.
-
#
-
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
-
# THE SOFTWARE.
-
#++
-
-
1
require 'date'
-
-
1
module TZInfo
-
# Represents an offset defined in a Timezone data file.
-
1
class TimezoneTransitionInfo #:nodoc:
-
# The offset this transition changes to (a TimezoneOffsetInfo instance).
-
1
attr_reader :offset
-
-
# The offset this transition changes from (a TimezoneOffsetInfo instance).
-
1
attr_reader :previous_offset
-
-
# The numerator of the DateTime if the transition time is defined as a
-
# DateTime, otherwise the transition time as a timestamp.
-
1
attr_reader :numerator_or_time
-
1
protected :numerator_or_time
-
-
# Either the denominotor of the DateTime if the transition time is defined
-
# as a DateTime, otherwise nil.
-
1
attr_reader :denominator
-
1
protected :denominator
-
-
# Creates a new TimezoneTransitionInfo with the given offset,
-
# previous_offset (both TimezoneOffsetInfo instances) and UTC time.
-
# if denominator is nil, numerator_or_time is treated as a number of
-
# seconds since the epoch. If denominator is specified numerator_or_time
-
# and denominator are used to create a DateTime as follows:
-
#
-
# DateTime.new!(Rational.send(:new!, numerator_or_time, denominator), 0, Date::ITALY)
-
#
-
# For performance reasons, the numerator and denominator must be specified
-
# in their lowest form.
-
1
def initialize(offset, previous_offset, numerator_or_time, denominator = nil)
-
10791
@offset = offset
-
10791
@previous_offset = previous_offset
-
10791
@numerator_or_time = numerator_or_time
-
10791
@denominator = denominator
-
-
10791
@at = nil
-
10791
@local_end = nil
-
10791
@local_start = nil
-
end
-
-
# A TimeOrDateTime instance representing the UTC time when this transition
-
# occurs.
-
1
def at
-
577
unless @at
-
226
unless @denominator
-
205
@at = TimeOrDateTime.new(@numerator_or_time)
-
else
-
21
r = RubyCoreSupport.rational_new!(@numerator_or_time, @denominator)
-
21
dt = RubyCoreSupport.datetime_new!(r, 0, Date::ITALY)
-
21
@at = TimeOrDateTime.new(dt)
-
end
-
end
-
-
577
@at
-
end
-
-
# A TimeOrDateTime instance representing the local time when this transition
-
# causes the previous observance to end (calculated from at using
-
# previous_offset).
-
1
def local_end
-
205
@local_end = at.add_with_convert(@previous_offset.utc_total_offset) unless @local_end
-
205
@local_end
-
end
-
-
# A TimeOrDateTime instance representing the local time when this transition
-
# causes the next observance to start (calculated from at using offset).
-
1
def local_start
-
294
@local_start = at.add_with_convert(@offset.utc_total_offset) unless @local_start
-
294
@local_start
-
end
-
-
# Returns true if this TimezoneTransitionInfo is equal to the given
-
# TimezoneTransitionInfo. Two TimezoneTransitionInfo instances are
-
# considered to be equal by == if offset, previous_offset and at are all
-
# equal.
-
1
def ==(tti)
-
tti.respond_to?(:offset) && tti.respond_to?(:previous_offset) && tti.respond_to?(:at) &&
-
offset == tti.offset && previous_offset == tti.previous_offset && at == tti.at
-
end
-
-
# Returns true if this TimezoneTransitionInfo is equal to the given
-
# TimezoneTransitionInfo. Two TimezoneTransitionInfo instances are
-
# considered to be equal by eql? if offset, previous_offset,
-
# numerator_or_time and denominator are all equal. This is stronger than ==,
-
# which just requires the at times to be equal regardless of how they were
-
# originally specified.
-
1
def eql?(tti)
-
tti.respond_to?(:offset) && tti.respond_to?(:previous_offset) &&
-
tti.respond_to?(:numerator_or_time) && tti.respond_to?(:denominator) &&
-
offset == tti.offset && previous_offset == tti.previous_offset &&
-
numerator_or_time == tti.numerator_or_time && denominator == tti.denominator
-
end
-
-
# Returns a hash of this TimezoneTransitionInfo instance.
-
1
def hash
-
@offset.hash ^ @previous_offset.hash ^ @numerator_or_time.hash ^ @denominator.hash
-
end
-
-
# Returns internal object state as a programmer-readable string.
-
1
def inspect
-
"#<#{self.class}: #{at.inspect},#{@offset.inspect}>"
-
end
-
end
-
end